Compare commits

..

1 Commits
v14.1 ... v13.0

Author SHA1 Message Date
Andrey Prygunkov
491fc1456e version 13.0 2014-07-14 20:51:33 +00:00
131 changed files with 4058 additions and 20014 deletions

29
AUTHORS
View File

@@ -1,27 +1,4 @@
NZBGet:
Andrey Prygunkov <hugbug@users.sourceforge.net> (versions 0.3.0 and later)
Bo Cordes Petersen <placebodk@users.sourceforge.net> (versions ? - 0.2.3)
nzbget:
Sven Henkel <sidddy@users.sourceforge.net> (versions 0.1.0 - ?)
PAR2:
Peter Brian Clements <peterbclements@users.sourceforge.net>
PAR2 library API:
Francois Lesueur <flesueur@users.sourceforge.net>
jQuery:
John Resig <http://jquery.com>
The Dojo Foundation <http://sizzlejs.com>
Bootstrap:
Twitter, Inc <http://twitter.github.com/bootstrap>
Raphaël:
Dmitry Baranovskiy <http://raphaeljs.com>
Sencha Labs <http://sencha.com>
Elycharts:
Void Labs s.n.c. <http://void.it>
iconSweets:
Yummygum <http://yummygum.com>
Bo Cordes Petersen <placebodk@users.sourceforge.net> (versions ? - 0.2.3)
Andrey Prygunkov <hugbug@users.sourceforge.net> (versions 0.3.0 and later)

1090
ChangeLog
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
#
# This file is part of nzbget
# This file if part of nzbget
#
# Copyright (C) 2008-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
@@ -52,12 +52,8 @@ nzbget_SOURCES = \
daemon/main/Options.h \
daemon/main/Scheduler.cpp \
daemon/main/Scheduler.h \
daemon/main/StackTrace.cpp \
daemon/main/StackTrace.h \
daemon/nntp/ArticleDownloader.cpp \
daemon/nntp/ArticleDownloader.h \
daemon/nntp/ArticleWriter.cpp \
daemon/nntp/ArticleWriter.h \
daemon/nntp/Decoder.cpp \
daemon/nntp/Decoder.h \
daemon/nntp/NewsServer.cpp \
@@ -123,52 +119,6 @@ nzbget_SOURCES = \
daemon/util/Util.h \
svn_version.cpp
if WITH_PAR2
nzbget_SOURCES += \
lib/par2/commandline.cpp \
lib/par2/commandline.h \
lib/par2/crc.cpp \
lib/par2/crc.h \
lib/par2/creatorpacket.cpp \
lib/par2/creatorpacket.h \
lib/par2/criticalpacket.cpp \
lib/par2/criticalpacket.h \
lib/par2/datablock.cpp \
lib/par2/datablock.h \
lib/par2/descriptionpacket.cpp \
lib/par2/descriptionpacket.h \
lib/par2/diskfile.cpp \
lib/par2/diskfile.h \
lib/par2/filechecksummer.cpp \
lib/par2/filechecksummer.h \
lib/par2/galois.cpp \
lib/par2/galois.h \
lib/par2/letype.h \
lib/par2/mainpacket.cpp \
lib/par2/mainpacket.h \
lib/par2/md5.cpp \
lib/par2/md5.h \
lib/par2/par2cmdline.h \
lib/par2/par2creatorsourcefile.cpp \
lib/par2/par2creatorsourcefile.h \
lib/par2/par2fileformat.cpp \
lib/par2/par2fileformat.h \
lib/par2/par2repairer.cpp \
lib/par2/par2repairer.h \
lib/par2/par2repairersourcefile.cpp \
lib/par2/par2repairersourcefile.h \
lib/par2/parheaders.cpp \
lib/par2/parheaders.h \
lib/par2/recoverypacket.cpp \
lib/par2/recoverypacket.h \
lib/par2/reedsolomon.cpp \
lib/par2/reedsolomon.h \
lib/par2/verificationhashtable.cpp \
lib/par2/verificationhashtable.h \
lib/par2/verificationpacket.cpp \
lib/par2/verificationpacket.h
endif
AM_CPPFLAGS = \
-I$(srcdir)/daemon/connect \
-I$(srcdir)/daemon/feed \
@@ -178,8 +128,7 @@ AM_CPPFLAGS = \
-I$(srcdir)/daemon/postprocess \
-I$(srcdir)/daemon/queue \
-I$(srcdir)/daemon/remote \
-I$(srcdir)/daemon/util \
-I$(srcdir)/lib/par2
-I$(srcdir)/daemon/util
EXTRA_DIST = \
Makefile.cvs \
@@ -219,6 +168,8 @@ osx_FILES = \
osx/Resources/Images/mainicon.icns \
osx/Resources/Images/statusicon.png \
osx/Resources/Images/statusicon@2x.png \
osx/Resources/Images/statusicon-inv.png \
osx/Resources/Images/statusicon-inv@2x.png \
osx/Resources/licenses/license-bootstrap.txt \
osx/Resources/licenses/license-jquery-GPL.txt \
osx/Resources/licenses/license-jquery-MIT.txt \
@@ -229,9 +180,7 @@ osx_FILES = \
doc_FILES = \
README \
ChangeLog \
COPYING \
lib/par2/AUTHORS \
lib/par2/README
COPYING
exampleconf_FILES = \
nzbget.conf
@@ -368,5 +317,4 @@ clean-bak: rm *~
dist-hook:
find $(distdir)/daemon -type f -print -exec chmod -x {} \;
find $(distdir)/webui -type f -print -exec chmod -x {} \;
find $(distdir)/lib -type f -print -exec chmod -x {} \;

View File

@@ -15,7 +15,7 @@
@SET_MAKE@
#
# This file is part of nzbget
# This file if part of nzbget
#
# Copyright (C) 2008-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
#
@@ -61,50 +61,6 @@ build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
bin_PROGRAMS = nzbget$(EXEEXT)
@WITH_PAR2_TRUE@am__append_1 = \
@WITH_PAR2_TRUE@ lib/par2/commandline.cpp \
@WITH_PAR2_TRUE@ lib/par2/commandline.h \
@WITH_PAR2_TRUE@ lib/par2/crc.cpp \
@WITH_PAR2_TRUE@ lib/par2/crc.h \
@WITH_PAR2_TRUE@ lib/par2/creatorpacket.cpp \
@WITH_PAR2_TRUE@ lib/par2/creatorpacket.h \
@WITH_PAR2_TRUE@ lib/par2/criticalpacket.cpp \
@WITH_PAR2_TRUE@ lib/par2/criticalpacket.h \
@WITH_PAR2_TRUE@ lib/par2/datablock.cpp \
@WITH_PAR2_TRUE@ lib/par2/datablock.h \
@WITH_PAR2_TRUE@ lib/par2/descriptionpacket.cpp \
@WITH_PAR2_TRUE@ lib/par2/descriptionpacket.h \
@WITH_PAR2_TRUE@ lib/par2/diskfile.cpp \
@WITH_PAR2_TRUE@ lib/par2/diskfile.h \
@WITH_PAR2_TRUE@ lib/par2/filechecksummer.cpp \
@WITH_PAR2_TRUE@ lib/par2/filechecksummer.h \
@WITH_PAR2_TRUE@ lib/par2/galois.cpp \
@WITH_PAR2_TRUE@ lib/par2/galois.h \
@WITH_PAR2_TRUE@ lib/par2/letype.h \
@WITH_PAR2_TRUE@ lib/par2/mainpacket.cpp \
@WITH_PAR2_TRUE@ lib/par2/mainpacket.h \
@WITH_PAR2_TRUE@ lib/par2/md5.cpp \
@WITH_PAR2_TRUE@ lib/par2/md5.h \
@WITH_PAR2_TRUE@ lib/par2/par2cmdline.h \
@WITH_PAR2_TRUE@ lib/par2/par2creatorsourcefile.cpp \
@WITH_PAR2_TRUE@ lib/par2/par2creatorsourcefile.h \
@WITH_PAR2_TRUE@ lib/par2/par2fileformat.cpp \
@WITH_PAR2_TRUE@ lib/par2/par2fileformat.h \
@WITH_PAR2_TRUE@ lib/par2/par2repairer.cpp \
@WITH_PAR2_TRUE@ lib/par2/par2repairer.h \
@WITH_PAR2_TRUE@ lib/par2/par2repairersourcefile.cpp \
@WITH_PAR2_TRUE@ lib/par2/par2repairersourcefile.h \
@WITH_PAR2_TRUE@ lib/par2/parheaders.cpp \
@WITH_PAR2_TRUE@ lib/par2/parheaders.h \
@WITH_PAR2_TRUE@ lib/par2/recoverypacket.cpp \
@WITH_PAR2_TRUE@ lib/par2/recoverypacket.h \
@WITH_PAR2_TRUE@ lib/par2/reedsolomon.cpp \
@WITH_PAR2_TRUE@ lib/par2/reedsolomon.h \
@WITH_PAR2_TRUE@ lib/par2/verificationhashtable.cpp \
@WITH_PAR2_TRUE@ lib/par2/verificationhashtable.h \
@WITH_PAR2_TRUE@ lib/par2/verificationpacket.cpp \
@WITH_PAR2_TRUE@ lib/par2/verificationpacket.h
DIST_COMMON = README $(am__configure_deps) $(dist_doc_DATA) \
$(dist_exampleconf_DATA) $(nobase_dist_scripts_SCRIPTS) \
$(nobase_dist_webui_DATA) $(srcdir)/Makefile.am \
@@ -126,106 +82,13 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(scriptsdir)" \
"$(DESTDIR)$(exampleconfdir)" "$(DESTDIR)$(webuidir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
am__nzbget_SOURCES_DIST = daemon/connect/Connection.cpp \
daemon/connect/Connection.h daemon/connect/TLS.cpp \
daemon/connect/TLS.h daemon/connect/WebDownloader.cpp \
daemon/connect/WebDownloader.h daemon/feed/FeedCoordinator.cpp \
daemon/feed/FeedCoordinator.h daemon/feed/FeedFile.cpp \
daemon/feed/FeedFile.h daemon/feed/FeedFilter.cpp \
daemon/feed/FeedFilter.h daemon/feed/FeedInfo.cpp \
daemon/feed/FeedInfo.h daemon/frontend/ColoredFrontend.cpp \
daemon/frontend/ColoredFrontend.h daemon/frontend/Frontend.cpp \
daemon/frontend/Frontend.h \
daemon/frontend/LoggableFrontend.cpp \
daemon/frontend/LoggableFrontend.h \
daemon/frontend/NCursesFrontend.cpp \
daemon/frontend/NCursesFrontend.h daemon/main/Maintenance.cpp \
daemon/main/Maintenance.h daemon/main/nzbget.cpp \
daemon/main/nzbget.h daemon/main/Options.cpp \
daemon/main/Options.h daemon/main/Scheduler.cpp \
daemon/main/Scheduler.h daemon/main/StackTrace.cpp \
daemon/main/StackTrace.h daemon/nntp/ArticleDownloader.cpp \
daemon/nntp/ArticleDownloader.h daemon/nntp/ArticleWriter.cpp \
daemon/nntp/ArticleWriter.h daemon/nntp/Decoder.cpp \
daemon/nntp/Decoder.h daemon/nntp/NewsServer.cpp \
daemon/nntp/NewsServer.h daemon/nntp/NNTPConnection.cpp \
daemon/nntp/NNTPConnection.h daemon/nntp/ServerPool.cpp \
daemon/nntp/ServerPool.h daemon/nntp/StatMeter.cpp \
daemon/nntp/StatMeter.h daemon/postprocess/ParChecker.cpp \
daemon/postprocess/ParChecker.h \
daemon/postprocess/ParCoordinator.cpp \
daemon/postprocess/ParCoordinator.h \
daemon/postprocess/ParRenamer.cpp \
daemon/postprocess/ParRenamer.h \
daemon/postprocess/PostScript.cpp \
daemon/postprocess/PostScript.h \
daemon/postprocess/PrePostProcessor.cpp \
daemon/postprocess/PrePostProcessor.h \
daemon/postprocess/Unpack.cpp daemon/postprocess/Unpack.h \
daemon/queue/DiskState.cpp daemon/queue/DiskState.h \
daemon/queue/DownloadInfo.cpp daemon/queue/DownloadInfo.h \
daemon/queue/DupeCoordinator.cpp \
daemon/queue/DupeCoordinator.h \
daemon/queue/HistoryCoordinator.cpp \
daemon/queue/HistoryCoordinator.h daemon/queue/NZBFile.cpp \
daemon/queue/NZBFile.h daemon/queue/QueueCoordinator.cpp \
daemon/queue/QueueCoordinator.h daemon/queue/QueueEditor.cpp \
daemon/queue/QueueEditor.h daemon/queue/QueueScript.cpp \
daemon/queue/QueueScript.h daemon/queue/Scanner.cpp \
daemon/queue/Scanner.h daemon/queue/UrlCoordinator.cpp \
daemon/queue/UrlCoordinator.h daemon/remote/BinRpc.cpp \
daemon/remote/BinRpc.h daemon/remote/MessageBase.h \
daemon/remote/RemoteClient.cpp daemon/remote/RemoteClient.h \
daemon/remote/RemoteServer.cpp daemon/remote/RemoteServer.h \
daemon/remote/WebServer.cpp daemon/remote/WebServer.h \
daemon/remote/XmlRpc.cpp daemon/remote/XmlRpc.h \
daemon/util/Log.cpp daemon/util/Log.h daemon/util/Observer.cpp \
daemon/util/Observer.h daemon/util/Script.cpp \
daemon/util/Script.h daemon/util/Thread.cpp \
daemon/util/Thread.h daemon/util/Util.cpp daemon/util/Util.h \
svn_version.cpp lib/par2/commandline.cpp \
lib/par2/commandline.h lib/par2/crc.cpp lib/par2/crc.h \
lib/par2/creatorpacket.cpp lib/par2/creatorpacket.h \
lib/par2/criticalpacket.cpp lib/par2/criticalpacket.h \
lib/par2/datablock.cpp lib/par2/datablock.h \
lib/par2/descriptionpacket.cpp lib/par2/descriptionpacket.h \
lib/par2/diskfile.cpp lib/par2/diskfile.h \
lib/par2/filechecksummer.cpp lib/par2/filechecksummer.h \
lib/par2/galois.cpp lib/par2/galois.h lib/par2/letype.h \
lib/par2/mainpacket.cpp lib/par2/mainpacket.h lib/par2/md5.cpp \
lib/par2/md5.h lib/par2/par2cmdline.h \
lib/par2/par2creatorsourcefile.cpp \
lib/par2/par2creatorsourcefile.h lib/par2/par2fileformat.cpp \
lib/par2/par2fileformat.h lib/par2/par2repairer.cpp \
lib/par2/par2repairer.h lib/par2/par2repairersourcefile.cpp \
lib/par2/par2repairersourcefile.h lib/par2/parheaders.cpp \
lib/par2/parheaders.h lib/par2/recoverypacket.cpp \
lib/par2/recoverypacket.h lib/par2/reedsolomon.cpp \
lib/par2/reedsolomon.h lib/par2/verificationhashtable.cpp \
lib/par2/verificationhashtable.h \
lib/par2/verificationpacket.cpp lib/par2/verificationpacket.h
@WITH_PAR2_TRUE@am__objects_1 = commandline.$(OBJEXT) crc.$(OBJEXT) \
@WITH_PAR2_TRUE@ creatorpacket.$(OBJEXT) \
@WITH_PAR2_TRUE@ criticalpacket.$(OBJEXT) datablock.$(OBJEXT) \
@WITH_PAR2_TRUE@ descriptionpacket.$(OBJEXT) diskfile.$(OBJEXT) \
@WITH_PAR2_TRUE@ filechecksummer.$(OBJEXT) galois.$(OBJEXT) \
@WITH_PAR2_TRUE@ mainpacket.$(OBJEXT) md5.$(OBJEXT) \
@WITH_PAR2_TRUE@ par2creatorsourcefile.$(OBJEXT) \
@WITH_PAR2_TRUE@ par2fileformat.$(OBJEXT) \
@WITH_PAR2_TRUE@ par2repairer.$(OBJEXT) \
@WITH_PAR2_TRUE@ par2repairersourcefile.$(OBJEXT) \
@WITH_PAR2_TRUE@ parheaders.$(OBJEXT) recoverypacket.$(OBJEXT) \
@WITH_PAR2_TRUE@ reedsolomon.$(OBJEXT) \
@WITH_PAR2_TRUE@ verificationhashtable.$(OBJEXT) \
@WITH_PAR2_TRUE@ verificationpacket.$(OBJEXT)
am_nzbget_OBJECTS = Connection.$(OBJEXT) TLS.$(OBJEXT) \
WebDownloader.$(OBJEXT) FeedCoordinator.$(OBJEXT) \
FeedFile.$(OBJEXT) FeedFilter.$(OBJEXT) FeedInfo.$(OBJEXT) \
ColoredFrontend.$(OBJEXT) Frontend.$(OBJEXT) \
LoggableFrontend.$(OBJEXT) NCursesFrontend.$(OBJEXT) \
Maintenance.$(OBJEXT) nzbget.$(OBJEXT) Options.$(OBJEXT) \
Scheduler.$(OBJEXT) StackTrace.$(OBJEXT) \
ArticleDownloader.$(OBJEXT) ArticleWriter.$(OBJEXT) \
Scheduler.$(OBJEXT) ArticleDownloader.$(OBJEXT) \
Decoder.$(OBJEXT) NewsServer.$(OBJEXT) \
NNTPConnection.$(OBJEXT) ServerPool.$(OBJEXT) \
StatMeter.$(OBJEXT) ParChecker.$(OBJEXT) \
@@ -239,7 +102,7 @@ am_nzbget_OBJECTS = Connection.$(OBJEXT) TLS.$(OBJEXT) \
RemoteClient.$(OBJEXT) RemoteServer.$(OBJEXT) \
WebServer.$(OBJEXT) XmlRpc.$(OBJEXT) Log.$(OBJEXT) \
Observer.$(OBJEXT) Script.$(OBJEXT) Thread.$(OBJEXT) \
Util.$(OBJEXT) svn_version.$(OBJEXT) $(am__objects_1)
Util.$(OBJEXT) svn_version.$(OBJEXT)
nzbget_OBJECTS = $(am_nzbget_OBJECTS)
nzbget_LDADD = $(LDADD)
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
@@ -264,7 +127,7 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(nzbget_SOURCES)
DIST_SOURCES = $(am__nzbget_SOURCES_DIST)
DIST_SOURCES = $(nzbget_SOURCES)
dist_docDATA_INSTALL = $(INSTALL_DATA)
dist_exampleconfDATA_INSTALL = $(INSTALL_DATA)
nobase_dist_webuiDATA_INSTALL = $(install_sh_DATA)
@@ -328,8 +191,6 @@ SHELL = @SHELL@
STRIP = @STRIP@
TAR = @TAR@
VERSION = @VERSION@
WITH_PAR2_FALSE = @WITH_PAR2_FALSE@
WITH_PAR2_TRUE = @WITH_PAR2_TRUE@
ac_ct_CXX = @ac_ct_CXX@
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
@@ -360,6 +221,8 @@ infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
libsigc_CFLAGS = @libsigc_CFLAGS@
libsigc_LIBS = @libsigc_LIBS@
libxml2_CFLAGS = @libxml2_CFLAGS@
libxml2_LIBS = @libxml2_LIBS@
localedir = @localedir@
@@ -381,32 +244,50 @@ target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
nzbget_SOURCES = daemon/connect/Connection.cpp \
daemon/connect/Connection.h daemon/connect/TLS.cpp \
daemon/connect/TLS.h daemon/connect/WebDownloader.cpp \
daemon/connect/WebDownloader.h daemon/feed/FeedCoordinator.cpp \
daemon/feed/FeedCoordinator.h daemon/feed/FeedFile.cpp \
daemon/feed/FeedFile.h daemon/feed/FeedFilter.cpp \
daemon/feed/FeedFilter.h daemon/feed/FeedInfo.cpp \
daemon/feed/FeedInfo.h daemon/frontend/ColoredFrontend.cpp \
daemon/frontend/ColoredFrontend.h daemon/frontend/Frontend.cpp \
nzbget_SOURCES = \
daemon/connect/Connection.cpp \
daemon/connect/Connection.h \
daemon/connect/TLS.cpp \
daemon/connect/TLS.h \
daemon/connect/WebDownloader.cpp \
daemon/connect/WebDownloader.h \
daemon/feed/FeedCoordinator.cpp \
daemon/feed/FeedCoordinator.h \
daemon/feed/FeedFile.cpp \
daemon/feed/FeedFile.h \
daemon/feed/FeedFilter.cpp \
daemon/feed/FeedFilter.h \
daemon/feed/FeedInfo.cpp \
daemon/feed/FeedInfo.h \
daemon/frontend/ColoredFrontend.cpp \
daemon/frontend/ColoredFrontend.h \
daemon/frontend/Frontend.cpp \
daemon/frontend/Frontend.h \
daemon/frontend/LoggableFrontend.cpp \
daemon/frontend/LoggableFrontend.h \
daemon/frontend/NCursesFrontend.cpp \
daemon/frontend/NCursesFrontend.h daemon/main/Maintenance.cpp \
daemon/main/Maintenance.h daemon/main/nzbget.cpp \
daemon/main/nzbget.h daemon/main/Options.cpp \
daemon/main/Options.h daemon/main/Scheduler.cpp \
daemon/main/Scheduler.h daemon/main/StackTrace.cpp \
daemon/main/StackTrace.h daemon/nntp/ArticleDownloader.cpp \
daemon/nntp/ArticleDownloader.h daemon/nntp/ArticleWriter.cpp \
daemon/nntp/ArticleWriter.h daemon/nntp/Decoder.cpp \
daemon/nntp/Decoder.h daemon/nntp/NewsServer.cpp \
daemon/nntp/NewsServer.h daemon/nntp/NNTPConnection.cpp \
daemon/nntp/NNTPConnection.h daemon/nntp/ServerPool.cpp \
daemon/nntp/ServerPool.h daemon/nntp/StatMeter.cpp \
daemon/nntp/StatMeter.h daemon/postprocess/ParChecker.cpp \
daemon/frontend/NCursesFrontend.h \
daemon/main/Maintenance.cpp \
daemon/main/Maintenance.h \
daemon/main/nzbget.cpp \
daemon/main/nzbget.h \
daemon/main/Options.cpp \
daemon/main/Options.h \
daemon/main/Scheduler.cpp \
daemon/main/Scheduler.h \
daemon/nntp/ArticleDownloader.cpp \
daemon/nntp/ArticleDownloader.h \
daemon/nntp/Decoder.cpp \
daemon/nntp/Decoder.h \
daemon/nntp/NewsServer.cpp \
daemon/nntp/NewsServer.h \
daemon/nntp/NNTPConnection.cpp \
daemon/nntp/NNTPConnection.h \
daemon/nntp/ServerPool.cpp \
daemon/nntp/ServerPool.h \
daemon/nntp/StatMeter.cpp \
daemon/nntp/StatMeter.h \
daemon/postprocess/ParChecker.cpp \
daemon/postprocess/ParChecker.h \
daemon/postprocess/ParCoordinator.cpp \
daemon/postprocess/ParCoordinator.h \
@@ -416,29 +297,51 @@ nzbget_SOURCES = daemon/connect/Connection.cpp \
daemon/postprocess/PostScript.h \
daemon/postprocess/PrePostProcessor.cpp \
daemon/postprocess/PrePostProcessor.h \
daemon/postprocess/Unpack.cpp daemon/postprocess/Unpack.h \
daemon/queue/DiskState.cpp daemon/queue/DiskState.h \
daemon/queue/DownloadInfo.cpp daemon/queue/DownloadInfo.h \
daemon/postprocess/Unpack.cpp \
daemon/postprocess/Unpack.h \
daemon/queue/DiskState.cpp \
daemon/queue/DiskState.h \
daemon/queue/DownloadInfo.cpp \
daemon/queue/DownloadInfo.h \
daemon/queue/DupeCoordinator.cpp \
daemon/queue/DupeCoordinator.h \
daemon/queue/HistoryCoordinator.cpp \
daemon/queue/HistoryCoordinator.h daemon/queue/NZBFile.cpp \
daemon/queue/NZBFile.h daemon/queue/QueueCoordinator.cpp \
daemon/queue/QueueCoordinator.h daemon/queue/QueueEditor.cpp \
daemon/queue/QueueEditor.h daemon/queue/QueueScript.cpp \
daemon/queue/QueueScript.h daemon/queue/Scanner.cpp \
daemon/queue/Scanner.h daemon/queue/UrlCoordinator.cpp \
daemon/queue/UrlCoordinator.h daemon/remote/BinRpc.cpp \
daemon/remote/BinRpc.h daemon/remote/MessageBase.h \
daemon/remote/RemoteClient.cpp daemon/remote/RemoteClient.h \
daemon/remote/RemoteServer.cpp daemon/remote/RemoteServer.h \
daemon/remote/WebServer.cpp daemon/remote/WebServer.h \
daemon/remote/XmlRpc.cpp daemon/remote/XmlRpc.h \
daemon/util/Log.cpp daemon/util/Log.h daemon/util/Observer.cpp \
daemon/util/Observer.h daemon/util/Script.cpp \
daemon/util/Script.h daemon/util/Thread.cpp \
daemon/util/Thread.h daemon/util/Util.cpp daemon/util/Util.h \
svn_version.cpp $(am__append_1)
daemon/queue/HistoryCoordinator.h \
daemon/queue/NZBFile.cpp \
daemon/queue/NZBFile.h \
daemon/queue/QueueCoordinator.cpp \
daemon/queue/QueueCoordinator.h \
daemon/queue/QueueEditor.cpp \
daemon/queue/QueueEditor.h \
daemon/queue/QueueScript.cpp \
daemon/queue/QueueScript.h \
daemon/queue/Scanner.cpp \
daemon/queue/Scanner.h \
daemon/queue/UrlCoordinator.cpp \
daemon/queue/UrlCoordinator.h \
daemon/remote/BinRpc.cpp \
daemon/remote/BinRpc.h \
daemon/remote/MessageBase.h \
daemon/remote/RemoteClient.cpp \
daemon/remote/RemoteClient.h \
daemon/remote/RemoteServer.cpp \
daemon/remote/RemoteServer.h \
daemon/remote/WebServer.cpp \
daemon/remote/WebServer.h \
daemon/remote/XmlRpc.cpp \
daemon/remote/XmlRpc.h \
daemon/util/Log.cpp \
daemon/util/Log.h \
daemon/util/Observer.cpp \
daemon/util/Observer.h \
daemon/util/Script.cpp \
daemon/util/Script.h \
daemon/util/Thread.cpp \
daemon/util/Thread.h \
daemon/util/Util.cpp \
daemon/util/Util.h \
svn_version.cpp
AM_CPPFLAGS = \
-I$(srcdir)/daemon/connect \
-I$(srcdir)/daemon/feed \
@@ -448,8 +351,7 @@ AM_CPPFLAGS = \
-I$(srcdir)/daemon/postprocess \
-I$(srcdir)/daemon/queue \
-I$(srcdir)/daemon/remote \
-I$(srcdir)/daemon/util \
-I$(srcdir)/lib/par2
-I$(srcdir)/daemon/util
EXTRA_DIST = \
Makefile.cvs \
@@ -489,6 +391,8 @@ osx_FILES = \
osx/Resources/Images/mainicon.icns \
osx/Resources/Images/statusicon.png \
osx/Resources/Images/statusicon@2x.png \
osx/Resources/Images/statusicon-inv.png \
osx/Resources/Images/statusicon-inv@2x.png \
osx/Resources/licenses/license-bootstrap.txt \
osx/Resources/licenses/license-jquery-GPL.txt \
osx/Resources/licenses/license-jquery-MIT.txt \
@@ -499,9 +403,7 @@ osx_FILES = \
doc_FILES = \
README \
ChangeLog \
COPYING \
lib/par2/AUTHORS \
lib/par2/README
COPYING
exampleconf_FILES = \
nzbget.conf
@@ -691,7 +593,6 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ArticleDownloader.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ArticleWriter.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BinRpc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ColoredFrontend.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Connection.Po@am__quote@
@@ -728,7 +629,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Scheduler.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Script.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerPool.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StackTrace.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StatMeter.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TLS.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Thread.Po@am__quote@
@@ -738,28 +638,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WebDownloader.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WebServer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commandline.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/creatorpacket.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/criticalpacket.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datablock.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/descriptionpacket.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diskfile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filechecksummer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/galois.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mainpacket.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nzbget.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/par2creatorsourcefile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/par2fileformat.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/par2repairer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/par2repairersourcefile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parheaders.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recoverypacket.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reedsolomon.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svn_version.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verificationhashtable.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verificationpacket.Po@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@@ -985,20 +865,6 @@ Scheduler.obj: daemon/main/Scheduler.cpp
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Scheduler.obj `if test -f 'daemon/main/Scheduler.cpp'; then $(CYGPATH_W) 'daemon/main/Scheduler.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/main/Scheduler.cpp'; fi`
StackTrace.o: daemon/main/StackTrace.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT StackTrace.o -MD -MP -MF "$(DEPDIR)/StackTrace.Tpo" -c -o StackTrace.o `test -f 'daemon/main/StackTrace.cpp' || echo '$(srcdir)/'`daemon/main/StackTrace.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/StackTrace.Tpo" "$(DEPDIR)/StackTrace.Po"; else rm -f "$(DEPDIR)/StackTrace.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/main/StackTrace.cpp' object='StackTrace.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o StackTrace.o `test -f 'daemon/main/StackTrace.cpp' || echo '$(srcdir)/'`daemon/main/StackTrace.cpp
StackTrace.obj: daemon/main/StackTrace.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT StackTrace.obj -MD -MP -MF "$(DEPDIR)/StackTrace.Tpo" -c -o StackTrace.obj `if test -f 'daemon/main/StackTrace.cpp'; then $(CYGPATH_W) 'daemon/main/StackTrace.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/main/StackTrace.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/StackTrace.Tpo" "$(DEPDIR)/StackTrace.Po"; else rm -f "$(DEPDIR)/StackTrace.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/main/StackTrace.cpp' object='StackTrace.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o StackTrace.obj `if test -f 'daemon/main/StackTrace.cpp'; then $(CYGPATH_W) 'daemon/main/StackTrace.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/main/StackTrace.cpp'; fi`
ArticleDownloader.o: daemon/nntp/ArticleDownloader.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ArticleDownloader.o -MD -MP -MF "$(DEPDIR)/ArticleDownloader.Tpo" -c -o ArticleDownloader.o `test -f 'daemon/nntp/ArticleDownloader.cpp' || echo '$(srcdir)/'`daemon/nntp/ArticleDownloader.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ArticleDownloader.Tpo" "$(DEPDIR)/ArticleDownloader.Po"; else rm -f "$(DEPDIR)/ArticleDownloader.Tpo"; exit 1; fi
@@ -1013,20 +879,6 @@ ArticleDownloader.obj: daemon/nntp/ArticleDownloader.cpp
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ArticleDownloader.obj `if test -f 'daemon/nntp/ArticleDownloader.cpp'; then $(CYGPATH_W) 'daemon/nntp/ArticleDownloader.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nntp/ArticleDownloader.cpp'; fi`
ArticleWriter.o: daemon/nntp/ArticleWriter.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ArticleWriter.o -MD -MP -MF "$(DEPDIR)/ArticleWriter.Tpo" -c -o ArticleWriter.o `test -f 'daemon/nntp/ArticleWriter.cpp' || echo '$(srcdir)/'`daemon/nntp/ArticleWriter.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ArticleWriter.Tpo" "$(DEPDIR)/ArticleWriter.Po"; else rm -f "$(DEPDIR)/ArticleWriter.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nntp/ArticleWriter.cpp' object='ArticleWriter.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ArticleWriter.o `test -f 'daemon/nntp/ArticleWriter.cpp' || echo '$(srcdir)/'`daemon/nntp/ArticleWriter.cpp
ArticleWriter.obj: daemon/nntp/ArticleWriter.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ArticleWriter.obj -MD -MP -MF "$(DEPDIR)/ArticleWriter.Tpo" -c -o ArticleWriter.obj `if test -f 'daemon/nntp/ArticleWriter.cpp'; then $(CYGPATH_W) 'daemon/nntp/ArticleWriter.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nntp/ArticleWriter.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ArticleWriter.Tpo" "$(DEPDIR)/ArticleWriter.Po"; else rm -f "$(DEPDIR)/ArticleWriter.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/nntp/ArticleWriter.cpp' object='ArticleWriter.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ArticleWriter.obj `if test -f 'daemon/nntp/ArticleWriter.cpp'; then $(CYGPATH_W) 'daemon/nntp/ArticleWriter.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/nntp/ArticleWriter.cpp'; fi`
Decoder.o: daemon/nntp/Decoder.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Decoder.o -MD -MP -MF "$(DEPDIR)/Decoder.Tpo" -c -o Decoder.o `test -f 'daemon/nntp/Decoder.cpp' || echo '$(srcdir)/'`daemon/nntp/Decoder.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Decoder.Tpo" "$(DEPDIR)/Decoder.Po"; else rm -f "$(DEPDIR)/Decoder.Tpo"; exit 1; fi
@@ -1460,286 +1312,6 @@ Util.obj: daemon/util/Util.cpp
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='daemon/util/Util.cpp' object='Util.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Util.obj `if test -f 'daemon/util/Util.cpp'; then $(CYGPATH_W) 'daemon/util/Util.cpp'; else $(CYGPATH_W) '$(srcdir)/daemon/util/Util.cpp'; fi`
commandline.o: lib/par2/commandline.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT commandline.o -MD -MP -MF "$(DEPDIR)/commandline.Tpo" -c -o commandline.o `test -f 'lib/par2/commandline.cpp' || echo '$(srcdir)/'`lib/par2/commandline.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/commandline.Tpo" "$(DEPDIR)/commandline.Po"; else rm -f "$(DEPDIR)/commandline.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/commandline.cpp' object='commandline.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o commandline.o `test -f 'lib/par2/commandline.cpp' || echo '$(srcdir)/'`lib/par2/commandline.cpp
commandline.obj: lib/par2/commandline.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT commandline.obj -MD -MP -MF "$(DEPDIR)/commandline.Tpo" -c -o commandline.obj `if test -f 'lib/par2/commandline.cpp'; then $(CYGPATH_W) 'lib/par2/commandline.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/commandline.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/commandline.Tpo" "$(DEPDIR)/commandline.Po"; else rm -f "$(DEPDIR)/commandline.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/commandline.cpp' object='commandline.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o commandline.obj `if test -f 'lib/par2/commandline.cpp'; then $(CYGPATH_W) 'lib/par2/commandline.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/commandline.cpp'; fi`
crc.o: lib/par2/crc.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT crc.o -MD -MP -MF "$(DEPDIR)/crc.Tpo" -c -o crc.o `test -f 'lib/par2/crc.cpp' || echo '$(srcdir)/'`lib/par2/crc.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/crc.Tpo" "$(DEPDIR)/crc.Po"; else rm -f "$(DEPDIR)/crc.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/crc.cpp' object='crc.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o crc.o `test -f 'lib/par2/crc.cpp' || echo '$(srcdir)/'`lib/par2/crc.cpp
crc.obj: lib/par2/crc.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT crc.obj -MD -MP -MF "$(DEPDIR)/crc.Tpo" -c -o crc.obj `if test -f 'lib/par2/crc.cpp'; then $(CYGPATH_W) 'lib/par2/crc.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/crc.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/crc.Tpo" "$(DEPDIR)/crc.Po"; else rm -f "$(DEPDIR)/crc.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/crc.cpp' object='crc.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o crc.obj `if test -f 'lib/par2/crc.cpp'; then $(CYGPATH_W) 'lib/par2/crc.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/crc.cpp'; fi`
creatorpacket.o: lib/par2/creatorpacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT creatorpacket.o -MD -MP -MF "$(DEPDIR)/creatorpacket.Tpo" -c -o creatorpacket.o `test -f 'lib/par2/creatorpacket.cpp' || echo '$(srcdir)/'`lib/par2/creatorpacket.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/creatorpacket.Tpo" "$(DEPDIR)/creatorpacket.Po"; else rm -f "$(DEPDIR)/creatorpacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/creatorpacket.cpp' object='creatorpacket.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o creatorpacket.o `test -f 'lib/par2/creatorpacket.cpp' || echo '$(srcdir)/'`lib/par2/creatorpacket.cpp
creatorpacket.obj: lib/par2/creatorpacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT creatorpacket.obj -MD -MP -MF "$(DEPDIR)/creatorpacket.Tpo" -c -o creatorpacket.obj `if test -f 'lib/par2/creatorpacket.cpp'; then $(CYGPATH_W) 'lib/par2/creatorpacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/creatorpacket.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/creatorpacket.Tpo" "$(DEPDIR)/creatorpacket.Po"; else rm -f "$(DEPDIR)/creatorpacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/creatorpacket.cpp' object='creatorpacket.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o creatorpacket.obj `if test -f 'lib/par2/creatorpacket.cpp'; then $(CYGPATH_W) 'lib/par2/creatorpacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/creatorpacket.cpp'; fi`
criticalpacket.o: lib/par2/criticalpacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT criticalpacket.o -MD -MP -MF "$(DEPDIR)/criticalpacket.Tpo" -c -o criticalpacket.o `test -f 'lib/par2/criticalpacket.cpp' || echo '$(srcdir)/'`lib/par2/criticalpacket.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/criticalpacket.Tpo" "$(DEPDIR)/criticalpacket.Po"; else rm -f "$(DEPDIR)/criticalpacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/criticalpacket.cpp' object='criticalpacket.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o criticalpacket.o `test -f 'lib/par2/criticalpacket.cpp' || echo '$(srcdir)/'`lib/par2/criticalpacket.cpp
criticalpacket.obj: lib/par2/criticalpacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT criticalpacket.obj -MD -MP -MF "$(DEPDIR)/criticalpacket.Tpo" -c -o criticalpacket.obj `if test -f 'lib/par2/criticalpacket.cpp'; then $(CYGPATH_W) 'lib/par2/criticalpacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/criticalpacket.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/criticalpacket.Tpo" "$(DEPDIR)/criticalpacket.Po"; else rm -f "$(DEPDIR)/criticalpacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/criticalpacket.cpp' object='criticalpacket.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o criticalpacket.obj `if test -f 'lib/par2/criticalpacket.cpp'; then $(CYGPATH_W) 'lib/par2/criticalpacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/criticalpacket.cpp'; fi`
datablock.o: lib/par2/datablock.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT datablock.o -MD -MP -MF "$(DEPDIR)/datablock.Tpo" -c -o datablock.o `test -f 'lib/par2/datablock.cpp' || echo '$(srcdir)/'`lib/par2/datablock.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/datablock.Tpo" "$(DEPDIR)/datablock.Po"; else rm -f "$(DEPDIR)/datablock.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/datablock.cpp' object='datablock.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o datablock.o `test -f 'lib/par2/datablock.cpp' || echo '$(srcdir)/'`lib/par2/datablock.cpp
datablock.obj: lib/par2/datablock.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT datablock.obj -MD -MP -MF "$(DEPDIR)/datablock.Tpo" -c -o datablock.obj `if test -f 'lib/par2/datablock.cpp'; then $(CYGPATH_W) 'lib/par2/datablock.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/datablock.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/datablock.Tpo" "$(DEPDIR)/datablock.Po"; else rm -f "$(DEPDIR)/datablock.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/datablock.cpp' object='datablock.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o datablock.obj `if test -f 'lib/par2/datablock.cpp'; then $(CYGPATH_W) 'lib/par2/datablock.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/datablock.cpp'; fi`
descriptionpacket.o: lib/par2/descriptionpacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT descriptionpacket.o -MD -MP -MF "$(DEPDIR)/descriptionpacket.Tpo" -c -o descriptionpacket.o `test -f 'lib/par2/descriptionpacket.cpp' || echo '$(srcdir)/'`lib/par2/descriptionpacket.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/descriptionpacket.Tpo" "$(DEPDIR)/descriptionpacket.Po"; else rm -f "$(DEPDIR)/descriptionpacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/descriptionpacket.cpp' object='descriptionpacket.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o descriptionpacket.o `test -f 'lib/par2/descriptionpacket.cpp' || echo '$(srcdir)/'`lib/par2/descriptionpacket.cpp
descriptionpacket.obj: lib/par2/descriptionpacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT descriptionpacket.obj -MD -MP -MF "$(DEPDIR)/descriptionpacket.Tpo" -c -o descriptionpacket.obj `if test -f 'lib/par2/descriptionpacket.cpp'; then $(CYGPATH_W) 'lib/par2/descriptionpacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/descriptionpacket.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/descriptionpacket.Tpo" "$(DEPDIR)/descriptionpacket.Po"; else rm -f "$(DEPDIR)/descriptionpacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/descriptionpacket.cpp' object='descriptionpacket.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o descriptionpacket.obj `if test -f 'lib/par2/descriptionpacket.cpp'; then $(CYGPATH_W) 'lib/par2/descriptionpacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/descriptionpacket.cpp'; fi`
diskfile.o: lib/par2/diskfile.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT diskfile.o -MD -MP -MF "$(DEPDIR)/diskfile.Tpo" -c -o diskfile.o `test -f 'lib/par2/diskfile.cpp' || echo '$(srcdir)/'`lib/par2/diskfile.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/diskfile.Tpo" "$(DEPDIR)/diskfile.Po"; else rm -f "$(DEPDIR)/diskfile.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/diskfile.cpp' object='diskfile.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o diskfile.o `test -f 'lib/par2/diskfile.cpp' || echo '$(srcdir)/'`lib/par2/diskfile.cpp
diskfile.obj: lib/par2/diskfile.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT diskfile.obj -MD -MP -MF "$(DEPDIR)/diskfile.Tpo" -c -o diskfile.obj `if test -f 'lib/par2/diskfile.cpp'; then $(CYGPATH_W) 'lib/par2/diskfile.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/diskfile.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/diskfile.Tpo" "$(DEPDIR)/diskfile.Po"; else rm -f "$(DEPDIR)/diskfile.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/diskfile.cpp' object='diskfile.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o diskfile.obj `if test -f 'lib/par2/diskfile.cpp'; then $(CYGPATH_W) 'lib/par2/diskfile.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/diskfile.cpp'; fi`
filechecksummer.o: lib/par2/filechecksummer.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filechecksummer.o -MD -MP -MF "$(DEPDIR)/filechecksummer.Tpo" -c -o filechecksummer.o `test -f 'lib/par2/filechecksummer.cpp' || echo '$(srcdir)/'`lib/par2/filechecksummer.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/filechecksummer.Tpo" "$(DEPDIR)/filechecksummer.Po"; else rm -f "$(DEPDIR)/filechecksummer.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/filechecksummer.cpp' object='filechecksummer.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filechecksummer.o `test -f 'lib/par2/filechecksummer.cpp' || echo '$(srcdir)/'`lib/par2/filechecksummer.cpp
filechecksummer.obj: lib/par2/filechecksummer.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filechecksummer.obj -MD -MP -MF "$(DEPDIR)/filechecksummer.Tpo" -c -o filechecksummer.obj `if test -f 'lib/par2/filechecksummer.cpp'; then $(CYGPATH_W) 'lib/par2/filechecksummer.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/filechecksummer.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/filechecksummer.Tpo" "$(DEPDIR)/filechecksummer.Po"; else rm -f "$(DEPDIR)/filechecksummer.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/filechecksummer.cpp' object='filechecksummer.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filechecksummer.obj `if test -f 'lib/par2/filechecksummer.cpp'; then $(CYGPATH_W) 'lib/par2/filechecksummer.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/filechecksummer.cpp'; fi`
galois.o: lib/par2/galois.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT galois.o -MD -MP -MF "$(DEPDIR)/galois.Tpo" -c -o galois.o `test -f 'lib/par2/galois.cpp' || echo '$(srcdir)/'`lib/par2/galois.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/galois.Tpo" "$(DEPDIR)/galois.Po"; else rm -f "$(DEPDIR)/galois.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/galois.cpp' object='galois.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o galois.o `test -f 'lib/par2/galois.cpp' || echo '$(srcdir)/'`lib/par2/galois.cpp
galois.obj: lib/par2/galois.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT galois.obj -MD -MP -MF "$(DEPDIR)/galois.Tpo" -c -o galois.obj `if test -f 'lib/par2/galois.cpp'; then $(CYGPATH_W) 'lib/par2/galois.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/galois.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/galois.Tpo" "$(DEPDIR)/galois.Po"; else rm -f "$(DEPDIR)/galois.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/galois.cpp' object='galois.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o galois.obj `if test -f 'lib/par2/galois.cpp'; then $(CYGPATH_W) 'lib/par2/galois.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/galois.cpp'; fi`
mainpacket.o: lib/par2/mainpacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainpacket.o -MD -MP -MF "$(DEPDIR)/mainpacket.Tpo" -c -o mainpacket.o `test -f 'lib/par2/mainpacket.cpp' || echo '$(srcdir)/'`lib/par2/mainpacket.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/mainpacket.Tpo" "$(DEPDIR)/mainpacket.Po"; else rm -f "$(DEPDIR)/mainpacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/mainpacket.cpp' object='mainpacket.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainpacket.o `test -f 'lib/par2/mainpacket.cpp' || echo '$(srcdir)/'`lib/par2/mainpacket.cpp
mainpacket.obj: lib/par2/mainpacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mainpacket.obj -MD -MP -MF "$(DEPDIR)/mainpacket.Tpo" -c -o mainpacket.obj `if test -f 'lib/par2/mainpacket.cpp'; then $(CYGPATH_W) 'lib/par2/mainpacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/mainpacket.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/mainpacket.Tpo" "$(DEPDIR)/mainpacket.Po"; else rm -f "$(DEPDIR)/mainpacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/mainpacket.cpp' object='mainpacket.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mainpacket.obj `if test -f 'lib/par2/mainpacket.cpp'; then $(CYGPATH_W) 'lib/par2/mainpacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/mainpacket.cpp'; fi`
md5.o: lib/par2/md5.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT md5.o -MD -MP -MF "$(DEPDIR)/md5.Tpo" -c -o md5.o `test -f 'lib/par2/md5.cpp' || echo '$(srcdir)/'`lib/par2/md5.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/md5.Tpo" "$(DEPDIR)/md5.Po"; else rm -f "$(DEPDIR)/md5.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/md5.cpp' object='md5.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o md5.o `test -f 'lib/par2/md5.cpp' || echo '$(srcdir)/'`lib/par2/md5.cpp
md5.obj: lib/par2/md5.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT md5.obj -MD -MP -MF "$(DEPDIR)/md5.Tpo" -c -o md5.obj `if test -f 'lib/par2/md5.cpp'; then $(CYGPATH_W) 'lib/par2/md5.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/md5.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/md5.Tpo" "$(DEPDIR)/md5.Po"; else rm -f "$(DEPDIR)/md5.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/md5.cpp' object='md5.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o md5.obj `if test -f 'lib/par2/md5.cpp'; then $(CYGPATH_W) 'lib/par2/md5.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/md5.cpp'; fi`
par2creatorsourcefile.o: lib/par2/par2creatorsourcefile.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT par2creatorsourcefile.o -MD -MP -MF "$(DEPDIR)/par2creatorsourcefile.Tpo" -c -o par2creatorsourcefile.o `test -f 'lib/par2/par2creatorsourcefile.cpp' || echo '$(srcdir)/'`lib/par2/par2creatorsourcefile.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/par2creatorsourcefile.Tpo" "$(DEPDIR)/par2creatorsourcefile.Po"; else rm -f "$(DEPDIR)/par2creatorsourcefile.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/par2creatorsourcefile.cpp' object='par2creatorsourcefile.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o par2creatorsourcefile.o `test -f 'lib/par2/par2creatorsourcefile.cpp' || echo '$(srcdir)/'`lib/par2/par2creatorsourcefile.cpp
par2creatorsourcefile.obj: lib/par2/par2creatorsourcefile.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT par2creatorsourcefile.obj -MD -MP -MF "$(DEPDIR)/par2creatorsourcefile.Tpo" -c -o par2creatorsourcefile.obj `if test -f 'lib/par2/par2creatorsourcefile.cpp'; then $(CYGPATH_W) 'lib/par2/par2creatorsourcefile.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/par2creatorsourcefile.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/par2creatorsourcefile.Tpo" "$(DEPDIR)/par2creatorsourcefile.Po"; else rm -f "$(DEPDIR)/par2creatorsourcefile.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/par2creatorsourcefile.cpp' object='par2creatorsourcefile.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o par2creatorsourcefile.obj `if test -f 'lib/par2/par2creatorsourcefile.cpp'; then $(CYGPATH_W) 'lib/par2/par2creatorsourcefile.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/par2creatorsourcefile.cpp'; fi`
par2fileformat.o: lib/par2/par2fileformat.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT par2fileformat.o -MD -MP -MF "$(DEPDIR)/par2fileformat.Tpo" -c -o par2fileformat.o `test -f 'lib/par2/par2fileformat.cpp' || echo '$(srcdir)/'`lib/par2/par2fileformat.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/par2fileformat.Tpo" "$(DEPDIR)/par2fileformat.Po"; else rm -f "$(DEPDIR)/par2fileformat.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/par2fileformat.cpp' object='par2fileformat.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o par2fileformat.o `test -f 'lib/par2/par2fileformat.cpp' || echo '$(srcdir)/'`lib/par2/par2fileformat.cpp
par2fileformat.obj: lib/par2/par2fileformat.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT par2fileformat.obj -MD -MP -MF "$(DEPDIR)/par2fileformat.Tpo" -c -o par2fileformat.obj `if test -f 'lib/par2/par2fileformat.cpp'; then $(CYGPATH_W) 'lib/par2/par2fileformat.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/par2fileformat.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/par2fileformat.Tpo" "$(DEPDIR)/par2fileformat.Po"; else rm -f "$(DEPDIR)/par2fileformat.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/par2fileformat.cpp' object='par2fileformat.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o par2fileformat.obj `if test -f 'lib/par2/par2fileformat.cpp'; then $(CYGPATH_W) 'lib/par2/par2fileformat.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/par2fileformat.cpp'; fi`
par2repairer.o: lib/par2/par2repairer.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT par2repairer.o -MD -MP -MF "$(DEPDIR)/par2repairer.Tpo" -c -o par2repairer.o `test -f 'lib/par2/par2repairer.cpp' || echo '$(srcdir)/'`lib/par2/par2repairer.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/par2repairer.Tpo" "$(DEPDIR)/par2repairer.Po"; else rm -f "$(DEPDIR)/par2repairer.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/par2repairer.cpp' object='par2repairer.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o par2repairer.o `test -f 'lib/par2/par2repairer.cpp' || echo '$(srcdir)/'`lib/par2/par2repairer.cpp
par2repairer.obj: lib/par2/par2repairer.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT par2repairer.obj -MD -MP -MF "$(DEPDIR)/par2repairer.Tpo" -c -o par2repairer.obj `if test -f 'lib/par2/par2repairer.cpp'; then $(CYGPATH_W) 'lib/par2/par2repairer.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/par2repairer.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/par2repairer.Tpo" "$(DEPDIR)/par2repairer.Po"; else rm -f "$(DEPDIR)/par2repairer.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/par2repairer.cpp' object='par2repairer.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o par2repairer.obj `if test -f 'lib/par2/par2repairer.cpp'; then $(CYGPATH_W) 'lib/par2/par2repairer.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/par2repairer.cpp'; fi`
par2repairersourcefile.o: lib/par2/par2repairersourcefile.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT par2repairersourcefile.o -MD -MP -MF "$(DEPDIR)/par2repairersourcefile.Tpo" -c -o par2repairersourcefile.o `test -f 'lib/par2/par2repairersourcefile.cpp' || echo '$(srcdir)/'`lib/par2/par2repairersourcefile.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/par2repairersourcefile.Tpo" "$(DEPDIR)/par2repairersourcefile.Po"; else rm -f "$(DEPDIR)/par2repairersourcefile.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/par2repairersourcefile.cpp' object='par2repairersourcefile.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o par2repairersourcefile.o `test -f 'lib/par2/par2repairersourcefile.cpp' || echo '$(srcdir)/'`lib/par2/par2repairersourcefile.cpp
par2repairersourcefile.obj: lib/par2/par2repairersourcefile.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT par2repairersourcefile.obj -MD -MP -MF "$(DEPDIR)/par2repairersourcefile.Tpo" -c -o par2repairersourcefile.obj `if test -f 'lib/par2/par2repairersourcefile.cpp'; then $(CYGPATH_W) 'lib/par2/par2repairersourcefile.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/par2repairersourcefile.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/par2repairersourcefile.Tpo" "$(DEPDIR)/par2repairersourcefile.Po"; else rm -f "$(DEPDIR)/par2repairersourcefile.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/par2repairersourcefile.cpp' object='par2repairersourcefile.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o par2repairersourcefile.obj `if test -f 'lib/par2/par2repairersourcefile.cpp'; then $(CYGPATH_W) 'lib/par2/par2repairersourcefile.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/par2repairersourcefile.cpp'; fi`
parheaders.o: lib/par2/parheaders.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parheaders.o -MD -MP -MF "$(DEPDIR)/parheaders.Tpo" -c -o parheaders.o `test -f 'lib/par2/parheaders.cpp' || echo '$(srcdir)/'`lib/par2/parheaders.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/parheaders.Tpo" "$(DEPDIR)/parheaders.Po"; else rm -f "$(DEPDIR)/parheaders.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/parheaders.cpp' object='parheaders.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parheaders.o `test -f 'lib/par2/parheaders.cpp' || echo '$(srcdir)/'`lib/par2/parheaders.cpp
parheaders.obj: lib/par2/parheaders.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parheaders.obj -MD -MP -MF "$(DEPDIR)/parheaders.Tpo" -c -o parheaders.obj `if test -f 'lib/par2/parheaders.cpp'; then $(CYGPATH_W) 'lib/par2/parheaders.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/parheaders.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/parheaders.Tpo" "$(DEPDIR)/parheaders.Po"; else rm -f "$(DEPDIR)/parheaders.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/parheaders.cpp' object='parheaders.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parheaders.obj `if test -f 'lib/par2/parheaders.cpp'; then $(CYGPATH_W) 'lib/par2/parheaders.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/parheaders.cpp'; fi`
recoverypacket.o: lib/par2/recoverypacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT recoverypacket.o -MD -MP -MF "$(DEPDIR)/recoverypacket.Tpo" -c -o recoverypacket.o `test -f 'lib/par2/recoverypacket.cpp' || echo '$(srcdir)/'`lib/par2/recoverypacket.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/recoverypacket.Tpo" "$(DEPDIR)/recoverypacket.Po"; else rm -f "$(DEPDIR)/recoverypacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/recoverypacket.cpp' object='recoverypacket.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o recoverypacket.o `test -f 'lib/par2/recoverypacket.cpp' || echo '$(srcdir)/'`lib/par2/recoverypacket.cpp
recoverypacket.obj: lib/par2/recoverypacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT recoverypacket.obj -MD -MP -MF "$(DEPDIR)/recoverypacket.Tpo" -c -o recoverypacket.obj `if test -f 'lib/par2/recoverypacket.cpp'; then $(CYGPATH_W) 'lib/par2/recoverypacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/recoverypacket.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/recoverypacket.Tpo" "$(DEPDIR)/recoverypacket.Po"; else rm -f "$(DEPDIR)/recoverypacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/recoverypacket.cpp' object='recoverypacket.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o recoverypacket.obj `if test -f 'lib/par2/recoverypacket.cpp'; then $(CYGPATH_W) 'lib/par2/recoverypacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/recoverypacket.cpp'; fi`
reedsolomon.o: lib/par2/reedsolomon.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT reedsolomon.o -MD -MP -MF "$(DEPDIR)/reedsolomon.Tpo" -c -o reedsolomon.o `test -f 'lib/par2/reedsolomon.cpp' || echo '$(srcdir)/'`lib/par2/reedsolomon.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/reedsolomon.Tpo" "$(DEPDIR)/reedsolomon.Po"; else rm -f "$(DEPDIR)/reedsolomon.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/reedsolomon.cpp' object='reedsolomon.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o reedsolomon.o `test -f 'lib/par2/reedsolomon.cpp' || echo '$(srcdir)/'`lib/par2/reedsolomon.cpp
reedsolomon.obj: lib/par2/reedsolomon.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT reedsolomon.obj -MD -MP -MF "$(DEPDIR)/reedsolomon.Tpo" -c -o reedsolomon.obj `if test -f 'lib/par2/reedsolomon.cpp'; then $(CYGPATH_W) 'lib/par2/reedsolomon.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/reedsolomon.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/reedsolomon.Tpo" "$(DEPDIR)/reedsolomon.Po"; else rm -f "$(DEPDIR)/reedsolomon.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/reedsolomon.cpp' object='reedsolomon.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o reedsolomon.obj `if test -f 'lib/par2/reedsolomon.cpp'; then $(CYGPATH_W) 'lib/par2/reedsolomon.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/reedsolomon.cpp'; fi`
verificationhashtable.o: lib/par2/verificationhashtable.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT verificationhashtable.o -MD -MP -MF "$(DEPDIR)/verificationhashtable.Tpo" -c -o verificationhashtable.o `test -f 'lib/par2/verificationhashtable.cpp' || echo '$(srcdir)/'`lib/par2/verificationhashtable.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/verificationhashtable.Tpo" "$(DEPDIR)/verificationhashtable.Po"; else rm -f "$(DEPDIR)/verificationhashtable.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/verificationhashtable.cpp' object='verificationhashtable.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o verificationhashtable.o `test -f 'lib/par2/verificationhashtable.cpp' || echo '$(srcdir)/'`lib/par2/verificationhashtable.cpp
verificationhashtable.obj: lib/par2/verificationhashtable.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT verificationhashtable.obj -MD -MP -MF "$(DEPDIR)/verificationhashtable.Tpo" -c -o verificationhashtable.obj `if test -f 'lib/par2/verificationhashtable.cpp'; then $(CYGPATH_W) 'lib/par2/verificationhashtable.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/verificationhashtable.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/verificationhashtable.Tpo" "$(DEPDIR)/verificationhashtable.Po"; else rm -f "$(DEPDIR)/verificationhashtable.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/verificationhashtable.cpp' object='verificationhashtable.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o verificationhashtable.obj `if test -f 'lib/par2/verificationhashtable.cpp'; then $(CYGPATH_W) 'lib/par2/verificationhashtable.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/verificationhashtable.cpp'; fi`
verificationpacket.o: lib/par2/verificationpacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT verificationpacket.o -MD -MP -MF "$(DEPDIR)/verificationpacket.Tpo" -c -o verificationpacket.o `test -f 'lib/par2/verificationpacket.cpp' || echo '$(srcdir)/'`lib/par2/verificationpacket.cpp; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/verificationpacket.Tpo" "$(DEPDIR)/verificationpacket.Po"; else rm -f "$(DEPDIR)/verificationpacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/verificationpacket.cpp' object='verificationpacket.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o verificationpacket.o `test -f 'lib/par2/verificationpacket.cpp' || echo '$(srcdir)/'`lib/par2/verificationpacket.cpp
verificationpacket.obj: lib/par2/verificationpacket.cpp
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT verificationpacket.obj -MD -MP -MF "$(DEPDIR)/verificationpacket.Tpo" -c -o verificationpacket.obj `if test -f 'lib/par2/verificationpacket.cpp'; then $(CYGPATH_W) 'lib/par2/verificationpacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/verificationpacket.cpp'; fi`; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/verificationpacket.Tpo" "$(DEPDIR)/verificationpacket.Po"; else rm -f "$(DEPDIR)/verificationpacket.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lib/par2/verificationpacket.cpp' object='verificationpacket.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o verificationpacket.obj `if test -f 'lib/par2/verificationpacket.cpp'; then $(CYGPATH_W) 'lib/par2/verificationpacket.cpp'; else $(CYGPATH_W) '$(srcdir)/lib/par2/verificationpacket.cpp'; fi`
uninstall-info-am:
install-dist_docDATA: $(dist_doc_DATA)
@$(NORMAL_INSTALL)
@@ -1846,7 +1418,7 @@ distclean-tags:
distdir: $(DISTFILES)
$(am__remove_distdir)
mkdir $(distdir)
$(mkdir_p) $(distdir)/daemon/windows $(distdir)/lib/par2 $(distdir)/osx $(distdir)/osx/NZBGet.xcodeproj $(distdir)/osx/Resources $(distdir)/osx/Resources/Images $(distdir)/osx/Resources/licenses $(distdir)/scripts $(distdir)/webui $(distdir)/webui/img $(distdir)/webui/lib
$(mkdir_p) $(distdir)/daemon/windows $(distdir)/osx $(distdir)/osx/NZBGet.xcodeproj $(distdir)/osx/Resources $(distdir)/osx/Resources/Images $(distdir)/osx/Resources/licenses $(distdir)/scripts $(distdir)/webui $(distdir)/webui/img $(distdir)/webui/lib
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
list='$(DISTFILES)'; for file in $$list; do \
@@ -2167,7 +1739,6 @@ clean-bak: rm *~
dist-hook:
find $(distdir)/daemon -type f -print -exec chmod -x {} \;
find $(distdir)/webui -type f -print -exec chmod -x {} \;
find $(distdir)/lib -type f -print -exec chmod -x {} \;
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

87
README
View File

@@ -85,7 +85,12 @@ And the following libraries are optional:
- libcurses (usually part of commercial systems)
or (better)
- libncurses (http://invisible-island.net/ncurses)
- for par-check and -repair (enabled by default):
- libpar2 (http://launchpad.net/libpar2,
http://parchive.sourceforge.net)
- libsigc++ (http://libsigc.sourceforge.net)
- for encrypted connections (TLS/SSL):
- OpenSSL (http://www.openssl.org)
or
@@ -147,7 +152,7 @@ You may run configure with additional arguments:
if you can not use curses/ncurses.
--disable-parcheck - to make without parcheck-support. Use this option
if you have troubles when compiling par2-module.
if you can not use libpar2 or libsigc++.
--with-tlslib=(OpenSSL, GnuTLS) - to select which TLS/SSL library
should be used for encrypted server connections.
@@ -164,13 +169,34 @@ You may run configure with additional arguments:
Optional package: par-check
---------------------------
NZBGet can check and repair downloaded files for you. For this purpose
it uses library par2.
it uses library par2 (libpar2), which needs sigc++ on its part.
For your convenience the source code of libpar2 is integrated into
NZBGets source tree and is compiled automatically when you make NZBGet.
The libpar2 and libsigc++ (version 2 or later) must be installed on your
system. On most linux distributions these libraries are available as packages.
If you do not have these packages you can compile them yourself.
Following configure-parameters may be usefull:
In a case errors occur during this process the inclusion of par2-module
can be disabled using configure option "--disable-parcheck":
--with-libpar2-includes
--with-libpar2-libraries
--with-libsigc-includes
--with-libsigc-libraries
The library libsigc++ must be installed first, since libpar2 requires it.
Official project libpar2 (http://parchive.sourceforge.net) has not been
updated for many years. The last official version of libpar 0.2 contains
known bugs which may crash the program during par-check. These bugs
have been fixed in the semi-official fork maintained by Debian/Ubuntu
team (http://launchpad.net/libpar2). It is highly recommended to use this
version of libpar2 (version 0.4 or newer) instead of the last official
version 0.2. Recent releases of Debian/Ubuntu include this libpar2 version.
NZBGets configure script checks the installed version of libpar2 and prints
an error if it is older than 0.4. The check can be suppressed if the update
of libpar2 is not possible.
If you are not able to use libpar2 or libsigc++ or do not want them you can
make nzbget without support for par-check using option "--disable-parcheck":
./configure --disable-parcheck
@@ -178,7 +204,7 @@ Optional package: curses
-------------------------
For curses-outputmode you need ncurses or curses on your system.
If you do not have one of them you can download and compile ncurses yourself.
Following configure-parameters may be useful:
Following configure-parameters may be usefull:
--with-libcurses-includes
--with-libcurses-libraries
@@ -219,15 +245,24 @@ NZBGet is developed using MS Visual C++ 2005. The project file and solution
are provided. If you use MS Visual C++ 2005 Express you need to download
and install Platform SDK.
To compile the program with TLS/SSL support you need either OpenSSL or GnuTLS:
To compile the program with par-check-support you also need the following
libraries:
- libsigc++ (http://libsigc.sourceforge.net)
- libpar2 (http://launchpad.net/libpar2,
http://parchive.sourceforge.net)
Download these libaries, then use patch-files provided with NZBGet to create
preconfigured project files and solutions for each library.
Look at http://gnuwin32.sourceforge.net/packages/patch.htm for info on how
to use patch-files, if you do not familiar with this technique.
To compile the program with TLS/SSL support you also need the library:
- OpenSSL (http://www.openssl.org)
or
- GnuTLS (http://www.gnu.org/software/gnutls)
Also required are:
- Regex (http://gnuwin32.sourceforge.net/packages/regex.htm)
- Zlib (http://gnuwin32.sourceforge.net/packages/zlib.htm)
=====================================
6. Configuration
=====================================
@@ -462,32 +497,6 @@ Bo Cordes Petersen (placebodk@users.sourceforge.net) until 2005.
In 2007 the abandoned project was overtaken by Andrey Prygunkov.
Since then the program has been completely rewritten.
NZBGet distribution archive includes additional components
written by other authors:
PAR2:
Peter Brian Clements <peterbclements@users.sourceforge.net>
PAR2 library API:
Francois Lesueur <flesueur@users.sourceforge.net>
jQuery:
John Resig <http://jquery.com>
The Dojo Foundation <http://sizzlejs.com>
Bootstrap:
Twitter, Inc <http://twitter.github.com/bootstrap>
Raphaël:
Dmitry Baranovskiy <http://raphaeljs.com>
Sencha Labs <http://sencha.com>
Elycharts:
Void Labs s.n.c. <http://void.it>
iconSweets:
Yummygum <http://yummygum.com>
=====================================
9. Copyright
=====================================

View File

@@ -3,17 +3,13 @@
/* Define to 1 to include debug-code */
#undef DEBUG
/* Define to 1 if deleting of files during reading of directory is not
properly supported by OS */
#undef DIRBROWSER_SNAPSHOT
/* Define to 1 to not use curses */
#undef DISABLE_CURSES
/* Define to 1 to disable gzip-support */
#undef DISABLE_GZIP
/* Define to 1 to disable par-verification and repair */
/* Define to 1 to disable smart par-verification and restoration */
#undef DISABLE_PARCHECK
/* Define to 1 to not use TLS/SSL */
@@ -35,16 +31,6 @@
/* Define to 1 if you have the <curses.h> header file. */
#undef HAVE_CURSES_H
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
*/
#undef HAVE_DIRENT_H
/* Define to 1 if you have the <endian.h> header file. */
#undef HAVE_ENDIAN_H
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
#undef HAVE_FSEEKO
/* Define to 1 if getaddrinfo is supported */
#undef HAVE_GETADDRINFO
@@ -60,12 +46,6 @@
/* Define to 1 if gethostbyname_r takes 6 arguments */
#undef HAVE_GETHOSTBYNAME_R_6
/* Define to 1 if you have the `getopt' function. */
#undef HAVE_GETOPT
/* Define to 1 if you have the <getopt.h> header file. */
#undef HAVE_GETOPT_H
/* Define to 1 if getopt_long is supported */
#undef HAVE_GETOPT_LONG
@@ -75,9 +55,6 @@
/* Define to 1 to use GnuTLS library for TLS/SSL-support. */
#undef HAVE_LIBGNUTLS
/* Define to 1 if you have the `memcpy' function. */
#undef HAVE_MEMCPY
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
@@ -87,56 +64,33 @@
/* Define to 1 if you have the <ncurses/ncurses.h> header file. */
#undef HAVE_NCURSES_NCURSES_H
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
#undef HAVE_NDIR_H
/* Define to 1 to use OpenSSL library for TLS/SSL-support. */
#undef HAVE_OPENSSL
/* Define to 1 if libpar2 has recent bugfixes-patch (version 2) */
#undef HAVE_PAR2_BUGFIXES_V2
/* Define to 1 if libpar2 supports cancelling (needs a special patch) */
#undef HAVE_PAR2_CANCEL
/* Define to 1 if you have the <regex.h> header file. */
#undef HAVE_REGEX_H
/* Define to 1 if _SC_NPROCESSORS_ONLN is present in unistd.h */
#undef HAVE_SC_NPROCESSORS_ONLN
/* Define to 1 if spinlocks are supported */
#undef HAVE_SPINLOCK
/* Define to 1 if stdbool.h conforms to C99. */
#undef HAVE_STDBOOL_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdio.h> header file. */
#undef HAVE_STDIO_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strcasecmp' function. */
#undef HAVE_STRCASECMP
/* Define to 1 if you have the `strchr' function. */
#undef HAVE_STRCHR
/* Define to 1 if you have the `stricmp' function. */
#undef HAVE_STRICMP
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_DIR_H
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_NDIR_H
/* Define to 1 if you have the <sys/prctl.h> header file. */
#undef HAVE_SYS_PRCTL_H
@@ -152,9 +106,6 @@
/* Define to 1 if variadic macros are supported */
#undef HAVE_VARIADIC_MACROS
/* Define to 1 if the system has the type `_Bool'. */
#undef HAVE__BOOL
/* Name of package */
#undef PACKAGE
@@ -185,27 +136,8 @@
/* 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
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
#undef _LARGEFILE_SOURCE
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t

2282
configure vendored
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +1,10 @@
#
# This file is part of nzbget
#
# Copyright (C) 2008-2014 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(nzbget, 14.1, hugbug@users.sourceforge.net)
AC_INIT(nzbget, 13.0, hugbug@users.sourceforge.net)
AC_CANONICAL_SYSTEM
AM_INIT_AUTOMAKE(nzbget, 14.1)
AM_INIT_AUTOMAKE(nzbget, 13.0)
AC_CONFIG_SRCDIR([daemon/main/nzbget.cpp])
AC_CONFIG_HEADERS([config.h])
@@ -164,7 +143,7 @@ fi
dnl
dnl Check if spinlocks are available
dnl cCheck if spinlocks are available
dnl
AC_CHECK_FUNC(pthread_spin_init,
[AC_DEFINE([HAVE_SPINLOCK], 1, [Define to 1 if spinlocks are supported])]
@@ -201,31 +180,6 @@ AC_TRY_COMPILE([
AC_DEFINE_UNQUOTED(SOCKLEN_T, $SOCKLEN_T, [Determine what socket length (socklen_t) data type is])
dnl
dnl Dir-browser's snapshot
dnl
AC_MSG_CHECKING(whether dir-browser snapshot workaround is needed)
if test "$target_vendor" == "apple"; then
AC_MSG_RESULT([[yes]])
AC_DEFINE([DIRBROWSER_SNAPSHOT], 1, [Define to 1 if deleting of files during reading of directory is not properly supported by OS])
else
AC_MSG_RESULT([[no]])
fi
dnl
dnl check cpu cores via sysconf
dnl
AC_MSG_CHECKING(for cpu cores via sysconf)
AC_TRY_COMPILE(
[#include <unistd.h>],
[ int a = _SC_NPROCESSORS_ONLN; ],
FOUND="yes"
AC_MSG_RESULT([[yes]])
AC_DEFINE([HAVE_SC_NPROCESSORS_ONLN], 1, [Define to 1 if _SC_NPROCESSORS_ONLN is present in unistd.h]),
FOUND="no")
dnl
dnl checks for libxml2 includes and libraries.
dnl
@@ -242,8 +196,7 @@ AC_ARG_WITH(libxml2_libraries,
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"))
[CPPFLAGS="${CPPFLAGS} $libxml2_CFLAGS"])
fi
AC_CHECK_HEADER(libxml/tree.h,,
AC_MSG_ERROR("libxml2 header files not found"))
@@ -299,37 +252,116 @@ fi
dnl
dnl Use par-checking. Deafult: yes.
dnl Use libpar2 for par-checking. Deafult: no
dnl
AC_MSG_CHECKING(whether to include code for par-checking)
AC_ARG_ENABLE(parcheck,
[AS_HELP_STRING([--disable-parcheck], [do not include par-check/-repair-support])],
[AS_HELP_STRING([--disable-parcheck], [do not include par-check/-repair-support (removes dependency from libpar2- and libsigc-libraries)])],
[ ENABLEPARCHECK=$enableval ],
[ ENABLEPARCHECK=yes] )
AC_MSG_RESULT($ENABLEPARCHECK)
if test "$ENABLEPARCHECK" = "yes"; then
dnl PAR2 checks.
dnl
dnl Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDBOOL
AC_HEADER_STDC
AC_CHECK_HEADERS([stdio.h] [endian.h] [getopt.h])
dnl Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_SIZE_T
AC_C_BIGENDIAN
AC_C_CONST
AC_C_INLINE
AC_FUNC_FSEEKO
dnl Checks for library functions.
AC_FUNC_MEMCMP
AC_CHECK_FUNCS([stricmp] [strcasecmp])
AC_CHECK_FUNCS([strchr] [memcpy])
AC_CHECK_FUNCS([getopt])
AM_CONDITIONAL(WITH_PAR2, true)
dnl checks for libsigc++ includes and libraries (required for libpar2).
dnl
AC_ARG_WITH(libsigc_includes,
[AS_HELP_STRING([--with-libsigc-includes=DIR], [libsigc++-2.0 include directory])],
[CPPFLAGS="${CPPFLAGS} -I${withval}"]
[INCVAL="yes"],
[INCVAL="no"])
AC_ARG_WITH(libsigc_libraries,
[AS_HELP_STRING([--with-libsigc-libraries=DIR], [libsigc++-2.0 library directory])],
[LDFLAGS="${LDFLAGS} -L${withval}"]
[CPPFLAGS="${CPPFLAGS} -I${withval}/sigc++-2.0/include"]
[LIBVAL="yes"],
[LIBVAL="no"])
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
PKG_CHECK_MODULES(libsigc, sigc++-2.0,
[LIBS="${LIBS} $libsigc_LIBS"]
[CPPFLAGS="${CPPFLAGS} $libsigc_CFLAGS"])
fi
AC_CHECK_HEADER(sigc++/type_traits.h,,
AC_MSG_ERROR("libsigc++-2.0 header files not found"))
dnl
dnl checks for libpar2 includes and libraries.
dnl
INCVAL="${LIBPREF}/include"
LIBVAL="${LIBPREF}/lib"
AC_ARG_WITH(libpar2_includes,
[AS_HELP_STRING([--with-libpar2-includes=DIR], [libpar2 include directory])],
[INCVAL="$withval"])
CPPFLAGS="${CPPFLAGS} -I${INCVAL}"
AC_CHECK_HEADER(libpar2/libpar2.h,,
AC_MSG_ERROR("libpar2 header files not found"))
AC_ARG_WITH(libpar2_libraries,
[AS_HELP_STRING([--with-libpar2-libraries=DIR], [libpar2 library directory])],
[LIBVAL="$withval"])
LDFLAGS="${LDFLAGS} -L${LIBVAL}"
AC_SEARCH_LIBS([_ZN12Par2RepairerC1Ev], [par2], ,
AC_MSG_ERROR("libpar2 library not found"))
dnl
dnl check if libpar2 library is linkable
dnl
AC_MSG_CHECKING(for libpar2 linking)
AC_TRY_LINK(
[#include <libpar2/par2cmdline.h>]
[#include <libpar2/par2repairer.h>]
[ class Repairer : public Par2Repairer { }; ],
[ Repairer* p = new Repairer(); ],
AC_MSG_RESULT([[yes]]),
AC_MSG_RESULT([[no]])
AC_MSG_ERROR("libpar2 library not found"))
dnl
dnl check if libpar2 has support for cancelling
dnl
AC_MSG_CHECKING(whether libpar2 supports cancelling)
AC_TRY_COMPILE(
[#include <libpar2/par2cmdline.h>]
[#include <libpar2/par2repairer.h>]
[ class Repairer : public Par2Repairer { void test() { cancelled = true; } }; ],
[],
AC_MSG_RESULT([[yes]])
AC_DEFINE([HAVE_PAR2_CANCEL], 1, [Define to 1 if libpar2 supports cancelling (needs a special patch)]),
AC_MSG_RESULT([[no]]))
dnl
dnl check if libpar2 has recent bugfixes-patch
dnl
AC_MSG_CHECKING(whether libpar2 has recent bugfixes)
AC_TRY_COMPILE(
[#include <libpar2/par2cmdline.h>]
[#include <libpar2/par2repairer.h>]
[ class Repairer : public Par2Repairer { void test() { BugfixesPatchVersion2(); } }; ],
[],
AC_MSG_RESULT([[yes]])
PAR2PATCHV2=yes
AC_DEFINE([HAVE_PAR2_BUGFIXES_V2], 1, [Define to 1 if libpar2 has recent bugfixes-patch (version 2)]),
AC_MSG_RESULT([[no]])
PAR2PATCHV2=no)
if test "$PAR2PATCHV2" = "no" ; then
AC_ARG_ENABLE(libpar2-bugfixes-check,
[AS_HELP_STRING([--disable-libpar2-bugfixes-check], [do not check libpar2 version])],
[ PAR2PATCHCHECK=$enableval ],
[ PAR2PATCHCHECK=yes] )
if test "$PAR2PATCHCHECK" = "yes"; then
AC_ERROR([Your version of libpar2 doesn't include the recent bugfixes. Please update libpar2 to version 0.4 or newer (http://launchpad.net/libpar2). If you cannot install a newer version of libpar2, you can use configure parameter --disable-libpar2-bugfixes-check to suppress the check. Please note however that in this case the program may crash during par-check/repair. The update is highly recommended!])
fi
fi
else
AC_DEFINE([DISABLE_PARCHECK],1,[Define to 1 to disable par-verification and repair])
AM_CONDITIONAL(WITH_PAR2, false)
AC_DEFINE([DISABLE_PARCHECK],1,[Define to 1 to disable smart par-verification and restoration])
fi
@@ -362,9 +394,10 @@ if test "$USETLS" = "yes"; then
[LIBVAL="yes"],
[LIBVAL="no"])
if test "$INCVAL" = "no" -o "$LIBVAL" = "no"; then
PKG_CHECK_MODULES([openssl], [openssl],
PKG_CHECK_MODULES(openssl, openssl,
[LIBS="${LIBS} $openssl_LIBS"]
[CPPFLAGS="${CPPFLAGS} $openssl_CFLAGS"],
FOUND=yes
FOUND=no)
fi
@@ -412,29 +445,10 @@ if test "$USETLS" = "yes"; then
fi
if test "$FOUND" = "yes"; then
AC_SEARCH_LIBS([gnutls_global_init], [gnutls],
FOUND=yes,
AC_SEARCH_LIBS([gcry_control], [gnutls gcrypt],
FOUND=yes,
FOUND=no),
FOUND=no)
if test "$FOUND" = "yes"; then
dnl gcrypt is optional
AC_MSG_CHECKING([whether gcrypt is needed])
AC_TRY_COMPILE(
[#include <gnutls/gnutls.h>]
[#if GNUTLS_VERSION_NUMBER <= 0x020b00]
[compile error]
[#endif],
[int a;],
AC_MSG_RESULT([no])
GCRYPT=no,
AC_MSG_RESULT([yes])
GCRYPT=yes)
if test "$GCRYPT" = "yes"; then
AC_CHECK_HEADER([gcrypt.h],
AC_SEARCH_LIBS([gcry_control], [gnutls gcrypt],
FOUND=yes,
FOUND=no),
FOUND=yes)
fi
fi
if test "$FOUND" = "no" -a "$TLSLIB" = "GnuTLS"; then
AC_MSG_ERROR([Couldn't find GnuTLS library])
fi

View File

@@ -207,7 +207,6 @@ WebDownloader::EStatus WebDownloader::Download()
return Status;
}
m_pConnection->SetTimeout(g_pOptions->GetUrlTimeout());
m_pConnection->SetSuppressErrors(false);
// connection
@@ -665,9 +664,9 @@ bool WebDownloader::PrepareFile()
error("Could not %s file %s", "create", szFilename);
return false;
}
if (g_pOptions->GetWriteBuffer() > 0)
if (g_pOptions->GetWriteBufferSize() > 0)
{
setvbuf(m_pOutFile, NULL, _IOFBF, g_pOptions->GetWriteBuffer() * 1024);
setvbuf(m_pOutFile, (char *)NULL, _IOFBF, g_pOptions->GetWriteBufferSize());
}
return true;

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013 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
@@ -330,7 +330,7 @@ bool FeedFilter::Term::Compile(char* szToken)
}
/*
* If pFeedItemInfo is NULL, only field name is validated
* If pFeedItemInfo is NULL, only field type info is returned
*/
bool FeedFilter::Term::GetFieldData(const char* szField, FeedItemInfo* pFeedItemInfo,
const char** StrValue, long long* IntValue)
@@ -408,11 +408,6 @@ bool FeedFilter::Term::GetFieldData(const char* szField, FeedItemInfo* pFeedItem
*IntValue = pFeedItemInfo ? pFeedItemInfo->GetDupeScore() : 0;
return true;
}
else if (!strcasecmp(szField, "dupestatus"))
{
*StrValue = pFeedItemInfo ? pFeedItemInfo->GetDupeStatus() : NULL;
return true;
}
else if (!strncasecmp(szField, "attr-", 5))
{
if (pFeedItemInfo)

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 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,10 +39,8 @@
#include "nzbget.h"
#include "FeedInfo.h"
#include "DupeCoordinator.h"
#include "Util.h"
extern DupeCoordinator* g_pDupeCoordinator;
FeedInfo::FeedInfo(int iID, const char* szName, const char* szUrl, int iInterval,
const char* szFilter, bool bPauseNzb, const char* szCategory, int iPriority)
@@ -51,7 +49,7 @@ FeedInfo::FeedInfo(int iID, const char* szName, const char* szUrl, int iInterval
m_szName = strdup(szName ? szName : "");
m_szUrl = strdup(szUrl ? szUrl : "");
m_szFilter = strdup(szFilter ? szFilter : "");
m_iFilterHash = Util::HashBJ96(m_szFilter, strlen(m_szFilter), 0);
m_iFilterHash = Util::HashBJ96(szFilter, strlen(szFilter), 0);
m_szCategory = strdup(szCategory ? szCategory : "");
m_iInterval = iInterval;
m_bPauseNzb = bPauseNzb;
@@ -147,7 +145,6 @@ FeedItemInfo::FeedItemInfo()
m_szDupeKey = NULL;
m_iDupeScore = 0;
m_eDupeMode = dmScore;
m_szDupeStatus = NULL;
}
FeedItemInfo::~FeedItemInfo()
@@ -161,7 +158,6 @@ FeedItemInfo::~FeedItemInfo()
free(m_szEpisode);
free(m_szAddCategory);
free(m_szDupeKey);
free(m_szDupeStatus);
}
void FeedItemInfo::SetTitle(const char* szTitle)
@@ -323,37 +319,6 @@ void FeedItemInfo::ParseSeasonEpisode()
}
}
const char* FeedItemInfo::GetDupeStatus()
{
if (!m_szDupeStatus)
{
const char* szDupeStatusName[] = { "", "QUEUED", "DOWNLOADING", "3", "SUCCESS", "5", "6", "7", "WARNING",
"9", "10", "11", "12", "13", "14", "15", "FAILURE" };
char szStatuses[200];
szStatuses[0] = '\0';
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
DupeCoordinator::EDupeStatus eDupeStatus = g_pDupeCoordinator->GetDupeStatus(pDownloadQueue, m_szTitle, m_szDupeKey);
DownloadQueue::Unlock();
for (int i = 1; i <= (int)DupeCoordinator::dsFailure; i = i << 1)
{
if (eDupeStatus & i)
{
if (*szStatuses)
{
strcat(szStatuses, ",");
}
strcat(szStatuses, szDupeStatusName[i]);
}
}
m_szDupeStatus = strdup(szStatuses);
}
return m_szDupeStatus;
}
FeedHistoryInfo::FeedHistoryInfo(const char* szUrl, FeedHistoryInfo::EStatus eStatus, time_t tLastSeen)
{

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 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
@@ -165,7 +165,6 @@ private:
char* m_szDupeKey;
int m_iDupeScore;
EDupeMode m_eDupeMode;
char* m_szDupeStatus;
SharedFeedData* m_pSharedFeedData;
Attributes m_Attributes;
@@ -220,7 +219,6 @@ public:
void SetDupeScore(int iDupeScore) { m_iDupeScore = iDupeScore; }
EDupeMode GetDupeMode() { return m_eDupeMode; }
void SetDupeMode(EDupeMode eDupeMode) { m_eDupeMode = eDupeMode; }
const char* GetDupeStatus();
Attributes* GetAttributes() { return &m_Attributes; }
};

View File

@@ -43,7 +43,6 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifndef WIN32
#include <unistd.h>
#endif

View File

@@ -25,7 +25,7 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config.h"
#endif
#ifdef WIN32
@@ -107,9 +107,8 @@ static const char* OPTION_NZBDIR = "NzbDir";
static const char* OPTION_WEBDIR = "WebDir";
static const char* OPTION_CONFIGTEMPLATE = "ConfigTemplate";
static const char* OPTION_SCRIPTDIR = "ScriptDir";
static const char* OPTION_CREATELOG = "CreateLog";
static const char* OPTION_LOGFILE = "LogFile";
static const char* OPTION_WRITELOG = "WriteLog";
static const char* OPTION_ROTATELOG = "RotateLog";
static const char* OPTION_APPENDCATEGORYDIR = "AppendCategoryDir";
static const char* OPTION_LOCKFILE = "LockFile";
static const char* OPTION_DAEMONUSERNAME = "DaemonUsername";
@@ -125,11 +124,11 @@ static const char* OPTION_SECUREPORT = "SecurePort";
static const char* OPTION_SECURECERT = "SecureCert";
static const char* OPTION_SECUREKEY = "SecureKey";
static const char* OPTION_AUTHORIZEDIP = "AuthorizedIP";
static const char* OPTION_ARTICLETIMEOUT = "ArticleTimeout";
static const char* OPTION_URLTIMEOUT = "UrlTimeout";
static const char* OPTION_CONNECTIONTIMEOUT = "ConnectionTimeout";
static const char* OPTION_SAVEQUEUE = "SaveQueue";
static const char* OPTION_RELOADQUEUE = "ReloadQueue";
static const char* OPTION_CREATEBROKENLOG = "CreateBrokenLog";
static const char* OPTION_RESETLOG = "ResetLog";
static const char* OPTION_DECODE = "Decode";
static const char* OPTION_RETRIES = "Retries";
static const char* OPTION_RETRYINTERVAL = "RetryInterval";
@@ -145,10 +144,7 @@ static const char* OPTION_DETAILTARGET = "DetailTarget";
static const char* OPTION_PARCHECK = "ParCheck";
static const char* OPTION_PARREPAIR = "ParRepair";
static const char* OPTION_PARSCAN = "ParScan";
static const char* OPTION_PARQUICK = "ParQuick";
static const char* OPTION_PARRENAME = "ParRename";
static const char* OPTION_PARBUFFER = "ParBuffer";
static const char* OPTION_PARTHREADS = "ParThreads";
static const char* OPTION_HEALTHCHECK = "HealthCheck";
static const char* OPTION_SCANSCRIPT = "ScanScript";
static const char* OPTION_QUEUESCRIPT = "QueueScript";
@@ -159,7 +155,7 @@ static const char* OPTION_CURSESTIME = "CursesTime";
static const char* OPTION_CURSESGROUP = "CursesGroup";
static const char* OPTION_CRCCHECK = "CrcCheck";
static const char* OPTION_DIRECTWRITE = "DirectWrite";
static const char* OPTION_WRITEBUFFER = "WriteBuffer";
static const char* OPTION_WRITEBUFFERSIZE = "WriteBufferSize";
static const char* OPTION_NZBDIRINTERVAL = "NzbDirInterval";
static const char* OPTION_NZBDIRFILEAGE = "NzbDirFileAge";
static const char* OPTION_PARCLEANUPQUEUE = "ParCleanupQueue";
@@ -185,8 +181,6 @@ static const char* OPTION_FEEDHISTORY = "FeedHistory";
static const char* OPTION_URLFORCE = "UrlForce";
static const char* OPTION_TIMECORRECTION = "TimeCorrection";
static const char* OPTION_PROPAGATIONDELAY = "PropagationDelay";
static const char* OPTION_ARTICLECACHE = "ArticleCache";
static const char* OPTION_EVENTINTERVAL = "EventInterval";
// obsolete options
static const char* OPTION_POSTLOGKIND = "PostLogKind";
@@ -205,8 +199,6 @@ static const char* OPTION_RELOADURLQUEUE = "ReloadUrlQueue";
static const char* OPTION_RELOADPOSTQUEUE = "ReloadPostQueue";
static const char* OPTION_NZBPROCESS = "NZBProcess";
static const char* OPTION_NZBADDEDPROCESS = "NZBAddedProcess";
static const char* OPTION_CREATELOG = "CreateLog";
static const char* OPTION_RESETLOG = "ResetLog";
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 };
@@ -218,7 +210,6 @@ static const char* SCAN_SCRIPT_SIGNATURE = "SCAN";
static const char* QUEUE_SCRIPT_SIGNATURE = "QUEUE";
static const char* SCHEDULER_SCRIPT_SIGNATURE = "SCHEDULER";
static const char* END_SCRIPT_SIGNATURE = " SCRIPT";
static const char* QUEUE_EVENTS_SIGNATURE = "### QUEUE EVENTS:";
#ifndef WIN32
const char* PossibleConfigLocations[] =
@@ -395,7 +386,6 @@ Options::Script::Script(const char* szName, const char* szLocation)
m_bScanScript = false;
m_bQueueScript = false;
m_bSchedulerScript = false;
m_szQueueEvents = NULL;
}
Options::Script::~Script()
@@ -403,7 +393,6 @@ Options::Script::~Script()
free(m_szName);
free(m_szLocation);
free(m_szDisplayName);
free(m_szQueueEvents);
}
void Options::Script::SetDisplayName(const char* szDisplayName)
@@ -412,28 +401,16 @@ void Options::Script::SetDisplayName(const char* szDisplayName)
m_szDisplayName = strdup(szDisplayName);
}
void Options::Script::SetQueueEvents(const char* szQueueEvents)
{
free(m_szQueueEvents);
m_szQueueEvents = szQueueEvents ? strdup(szQueueEvents) : NULL;
}
Options::Scripts::~Scripts()
{
Clear();
}
void Options::Scripts::Clear()
Options::ScriptList::~ScriptList()
{
for (iterator it = begin(); it != end(); it++)
{
delete *it;
}
clear();
}
Options::Script* Options::Scripts::Find(const char* szName)
Options::Script* Options::ScriptList::Find(const char* szName)
{
for (iterator it = begin(); it != end(); it++)
{
@@ -475,6 +452,7 @@ Options::Options(int argc, char* argv[])
m_bPauseScan = false;
m_bTempPauseDownload = false;
m_bCreateBrokenLog = false;
m_bResetLog = false;
m_iDownloadRate = 0;
m_iEditQueueAction = 0;
m_pEditQueueIDList = NULL;
@@ -487,8 +465,7 @@ Options::Options(int argc, char* argv[])
m_iAddPriority = 0;
m_szAddNZBFilename = NULL;
m_bAddPaused = false;
m_iArticleTimeout = 0;
m_iUrlTimeout = 0;
m_iConnectionTimeout = 0;
m_iTerminateTimeout = 0;
m_bServerMode = false;
m_bDaemonMode = false;
@@ -518,16 +495,12 @@ Options::Options(int argc, char* argv[])
m_iLogBufferSize = 0;
m_iLogLines = 0;
m_iWriteLogKind = 0;
m_eWriteLog = wlAppend;
m_iRotateLog = 0;
m_bCreateLog = false;
m_szLogFile = NULL;
m_eParCheck = pcManual;
m_bParRepair = false;
m_eParScan = psLimited;
m_bParQuick = true;
m_bParRename = false;
m_iParBuffer = 0;
m_iParThreads = 0;
m_eHealthCheck = hcNone;
m_szScriptOrder = NULL;
m_szPostScript = NULL;
@@ -541,7 +514,7 @@ Options::Options(int argc, char* argv[])
m_bCursesGroup = false;
m_bCrcCheck = false;
m_bDirectWrite = false;
m_iWriteBuffer = 0;
m_iWriteBufferSize = 0;
m_iNzbDirInterval = 0;
m_iNzbDirFileAge = 0;
m_bParCleanupQueue = false;
@@ -570,8 +543,6 @@ Options::Options(int argc, char* argv[])
m_iTimeCorrection = 0;
m_iLocalTimeOffset = 0;
m_iPropagationDelay = 0;
m_iArticleCache = 0;
m_iEventInterval = 0;
// Option "ConfigFile" will be initialized later, but we want
// to see it at the top of option list, so we add it first
@@ -634,8 +605,6 @@ Options::Options(int argc, char* argv[])
InitCategories();
InitScheduler();
InitFeeds();
InitScripts();
InitConfigTemplates();
if (m_bPrintOptions)
{
@@ -763,8 +732,7 @@ void Options::InitDefault()
SetOption(OPTION_WEBDIR, "");
SetOption(OPTION_CONFIGTEMPLATE, "");
SetOption(OPTION_SCRIPTDIR, "${MainDir}/scripts");
SetOption(OPTION_WRITELOG, "append");
SetOption(OPTION_ROTATELOG, "3");
SetOption(OPTION_CREATELOG, "yes");
SetOption(OPTION_APPENDCATEGORYDIR, "yes");
SetOption(OPTION_OUTPUTMODE, "curses");
SetOption(OPTION_DUPECHECK, "yes");
@@ -778,11 +746,11 @@ void Options::InitDefault()
SetOption(OPTION_SECURECERT, "");
SetOption(OPTION_SECUREKEY, "");
SetOption(OPTION_AUTHORIZEDIP, "");
SetOption(OPTION_ARTICLETIMEOUT, "60");
SetOption(OPTION_URLTIMEOUT, "60");
SetOption(OPTION_CONNECTIONTIMEOUT, "60");
SetOption(OPTION_SAVEQUEUE, "yes");
SetOption(OPTION_RELOADQUEUE, "yes");
SetOption(OPTION_CREATEBROKENLOG, "yes");
SetOption(OPTION_RESETLOG, "no");
SetOption(OPTION_DECODE, "yes");
SetOption(OPTION_RETRIES, "3");
SetOption(OPTION_RETRYINTERVAL, "10");
@@ -798,10 +766,7 @@ void Options::InitDefault()
SetOption(OPTION_PARCHECK, "auto");
SetOption(OPTION_PARREPAIR, "yes");
SetOption(OPTION_PARSCAN, "limited");
SetOption(OPTION_PARQUICK, "yes");
SetOption(OPTION_PARRENAME, "yes");
SetOption(OPTION_PARBUFFER, "16");
SetOption(OPTION_PARTHREADS, "1");
SetOption(OPTION_HEALTHCHECK, "none");
SetOption(OPTION_SCRIPTORDER, "");
SetOption(OPTION_POSTSCRIPT, "");
@@ -815,7 +780,7 @@ void Options::InitDefault()
SetOption(OPTION_CURSESGROUP, "no");
SetOption(OPTION_CRCCHECK, "yes");
SetOption(OPTION_DIRECTWRITE, "yes");
SetOption(OPTION_WRITEBUFFER, "0");
SetOption(OPTION_WRITEBUFFERSIZE, "0");
SetOption(OPTION_NZBDIRINTERVAL, "5");
SetOption(OPTION_NZBDIRFILEAGE, "60");
SetOption(OPTION_PARCLEANUPQUEUE, "yes");
@@ -844,8 +809,6 @@ void Options::InitDefault()
SetOption(OPTION_URLFORCE, "yes");
SetOption(OPTION_TIMECORRECTION, "0");
SetOption(OPTION_PROPAGATIONDELAY, "0");
SetOption(OPTION_ARTICLECACHE, "0");
SetOption(OPTION_EVENTINTERVAL, "0");
}
void Options::InitOptFile()
@@ -917,13 +880,28 @@ void Options::InitOptFile()
m_bConfigInitialized = true;
}
void Options::CheckDir(char** dir, const char* szOptionName,
const char* szParentDir, bool bAllowEmpty, bool bCreate)
void Options::CheckDir(char** dir, const char* szOptionName, bool bAllowEmpty, bool bCreate)
{
char* usedir = NULL;
const char* tempdir = GetOption(szOptionName);
if (Util::EmptyStr(tempdir))
if (tempdir && strlen(tempdir) > 0)
{
int len = strlen(tempdir);
usedir = (char*) malloc(len + 2);
strcpy(usedir, tempdir);
char ch = usedir[len-1];
if (ch == ALT_PATH_SEPARATOR)
{
usedir[len-1] = PATH_SEPARATOR;
}
else if (ch != PATH_SEPARATOR)
{
usedir[len] = PATH_SEPARATOR;
usedir[len + 1] = '\0';
}
Util::NormalizePathSeparators(usedir);
}
else
{
if (!bAllowEmpty)
{
@@ -933,45 +911,6 @@ void Options::CheckDir(char** dir, const char* szOptionName,
return;
}
int len = strlen(tempdir);
usedir = (char*)malloc(len + 2);
strcpy(usedir, tempdir);
char ch = usedir[len-1];
Util::NormalizePathSeparators(usedir);
if (ch != PATH_SEPARATOR)
{
usedir[len] = PATH_SEPARATOR;
usedir[len + 1] = '\0';
}
if (!(usedir[0] == PATH_SEPARATOR || usedir[0] == ALT_PATH_SEPARATOR ||
(usedir[0] && usedir[1] == ':')) &&
!Util::EmptyStr(szParentDir))
{
// convert relative path to absolute path
int plen = strlen(szParentDir);
int len2 = len + plen + 4;
char* usedir2 = (char*)malloc(len2);
if (szParentDir[plen-1] == PATH_SEPARATOR || szParentDir[plen-1] == ALT_PATH_SEPARATOR)
{
snprintf(usedir2, len2, "%s%s", szParentDir, usedir);
}
else
{
snprintf(usedir2, len2, "%s%c%s", szParentDir, PATH_SEPARATOR, usedir);
}
usedir2[len2-1] = '\0';
free(usedir);
usedir = usedir2;
Util::NormalizePathSeparators(usedir);
int ulen = strlen(usedir);
usedir[ulen-1] = '\0';
SetOption(szOptionName, usedir);
usedir[ulen-1] = PATH_SEPARATOR;
}
// Ensure the dir is created
char szErrBuf[1024];
if (bCreate && !Util::ForceDirectories(usedir, szErrBuf, sizeof(szErrBuf)))
@@ -983,14 +922,12 @@ void Options::CheckDir(char** dir, const char* szOptionName,
void Options::InitOptions()
{
const char* szMainDir = GetOption(OPTION_MAINDIR);
CheckDir(&m_szDestDir, OPTION_DESTDIR, szMainDir, false, false);
CheckDir(&m_szInterDir, OPTION_INTERDIR, szMainDir, true, true);
CheckDir(&m_szTempDir, OPTION_TEMPDIR, szMainDir, false, true);
CheckDir(&m_szQueueDir, OPTION_QUEUEDIR, szMainDir, false, true);
CheckDir(&m_szWebDir, OPTION_WEBDIR, NULL, true, false);
CheckDir(&m_szScriptDir, OPTION_SCRIPTDIR, szMainDir, true, false);
CheckDir(&m_szDestDir, OPTION_DESTDIR, false, false);
CheckDir(&m_szInterDir, OPTION_INTERDIR, true, true);
CheckDir(&m_szTempDir, OPTION_TEMPDIR, false, true);
CheckDir(&m_szQueueDir, OPTION_QUEUEDIR, false, true);
CheckDir(&m_szWebDir, OPTION_WEBDIR, true, false);
CheckDir(&m_szScriptDir, OPTION_SCRIPTDIR, true, false);
m_szConfigTemplate = strdup(GetOption(OPTION_CONFIGTEMPLATE));
m_szScriptOrder = strdup(GetOption(OPTION_SCRIPTORDER));
@@ -1012,8 +949,7 @@ void Options::InitOptions()
m_szParIgnoreExt = strdup(GetOption(OPTION_PARIGNOREEXT));
m_iDownloadRate = (int)(ParseFloatValue(OPTION_DOWNLOADRATE) * 1024);
m_iArticleTimeout = ParseIntValue(OPTION_ARTICLETIMEOUT, 10);
m_iUrlTimeout = ParseIntValue(OPTION_URLTIMEOUT, 10);
m_iConnectionTimeout = ParseIntValue(OPTION_CONNECTIONTIMEOUT, 10);
m_iTerminateTimeout = ParseIntValue(OPTION_TERMINATETIMEOUT, 10);
m_iRetries = ParseIntValue(OPTION_RETRIES, 10);
m_iRetryInterval = ParseIntValue(OPTION_RETRYINTERVAL, 10);
@@ -1021,10 +957,9 @@ void Options::InitOptions()
m_iSecurePort = ParseIntValue(OPTION_SECUREPORT, 10);
m_iUrlConnections = ParseIntValue(OPTION_URLCONNECTIONS, 10);
m_iLogBufferSize = ParseIntValue(OPTION_LOGBUFFERSIZE, 10);
m_iRotateLog = ParseIntValue(OPTION_ROTATELOG, 10);
m_iUMask = ParseIntValue(OPTION_UMASK, 8);
m_iUpdateInterval = ParseIntValue(OPTION_UPDATEINTERVAL, 10);
m_iWriteBuffer = ParseIntValue(OPTION_WRITEBUFFER, 10);
m_iWriteBufferSize = ParseIntValue(OPTION_WRITEBUFFERSIZE, 10);
m_iNzbDirInterval = ParseIntValue(OPTION_NZBDIRINTERVAL, 10);
m_iNzbDirFileAge = ParseIntValue(OPTION_NZBDIRFILEAGE, 10);
m_iDiskSpace = ParseIntValue(OPTION_DISKSPACE, 10);
@@ -1038,20 +973,17 @@ void Options::InitOptions()
}
m_iTimeCorrection *= 60;
m_iPropagationDelay = ParseIntValue(OPTION_PROPAGATIONDELAY, 10) * 60;
m_iArticleCache = ParseIntValue(OPTION_ARTICLECACHE, 10);
m_iEventInterval = ParseIntValue(OPTION_EVENTINTERVAL, 10);
m_iParBuffer = ParseIntValue(OPTION_PARBUFFER, 10);
m_iParThreads = ParseIntValue(OPTION_PARTHREADS, 10);
CheckDir(&m_szNzbDir, OPTION_NZBDIR, szMainDir, m_iNzbDirInterval == 0, true);
CheckDir(&m_szNzbDir, OPTION_NZBDIR, m_iNzbDirInterval == 0, true);
m_bCreateBrokenLog = (bool)ParseEnumValue(OPTION_CREATEBROKENLOG, BoolCount, BoolNames, BoolValues);
m_bResetLog = (bool)ParseEnumValue(OPTION_RESETLOG, BoolCount, BoolNames, BoolValues);
m_bAppendCategoryDir = (bool)ParseEnumValue(OPTION_APPENDCATEGORYDIR, BoolCount, BoolNames, BoolValues);
m_bContinuePartial = (bool)ParseEnumValue(OPTION_CONTINUEPARTIAL, BoolCount, BoolNames, BoolValues);
m_bSaveQueue = (bool)ParseEnumValue(OPTION_SAVEQUEUE, BoolCount, BoolNames, BoolValues);
m_bDupeCheck = (bool)ParseEnumValue(OPTION_DUPECHECK, BoolCount, BoolNames, BoolValues);
m_bCreateLog = (bool)ParseEnumValue(OPTION_CREATELOG, BoolCount, BoolNames, BoolValues);
m_bParRepair = (bool)ParseEnumValue(OPTION_PARREPAIR, BoolCount, BoolNames, BoolValues);
m_bParQuick = (bool)ParseEnumValue(OPTION_PARQUICK, BoolCount, BoolNames, BoolValues);
m_bParRename = (bool)ParseEnumValue(OPTION_PARRENAME, BoolCount, BoolNames, BoolValues);
m_bReloadQueue = (bool)ParseEnumValue(OPTION_RELOADQUEUE, BoolCount, BoolNames, BoolValues);
m_bCursesNZBName = (bool)ParseEnumValue(OPTION_CURSESNZBNAME, BoolCount, BoolNames, BoolValues);
@@ -1101,11 +1033,6 @@ void Options::InitOptions()
m_eErrorTarget = (EMessageTarget)ParseEnumValue(OPTION_ERRORTARGET, TargetCount, TargetNames, TargetValues);
m_eDebugTarget = (EMessageTarget)ParseEnumValue(OPTION_DEBUGTARGET, TargetCount, TargetNames, TargetValues);
m_eDetailTarget = (EMessageTarget)ParseEnumValue(OPTION_DETAILTARGET, TargetCount, TargetNames, TargetValues);
const char* WriteLogNames[] = { "none", "append", "reset", "rotate" };
const int WriteLogValues[] = { wlNone, wlAppend, wlReset, wlRotate };
const int WriteLogCount = 4;
m_eWriteLog = (EWriteLog)ParseEnumValue(OPTION_WRITELOG, WriteLogCount, WriteLogNames, WriteLogValues);
}
int Options::ParseEnumValue(const char* OptName, int argc, const char * argn[], const int argv[])
@@ -1115,6 +1042,7 @@ int Options::ParseEnumValue(const char* OptName, int argc, const char * argn[],
{
ConfigError("Undefined value for option \"%s\"", OptName);
return argv[0];
//abort("FATAL ERROR: Undefined value for option \"%s\"\n", OptName);
}
int iDefNum = 0;
@@ -1800,7 +1728,7 @@ void Options::PrintUsage(char* com)
" <Names> List of names (with options \"FN\" and \"GN\"),\n"
" e. g.: \"my nzb download%cmyfile.nfo\" \"another nzb\"\n"
" <RegExs> List of regular expressions (options \"FR\", \"GR\")\n"
" using POSIX Extended Regular Expression Syntax\n",
" using POSIX Extended Regular Expression Syntax",
Util::BaseFileName(com),
PATH_SEPARATOR);
}
@@ -1873,16 +1801,6 @@ void Options::InitFileArg(int argc, char* argv[])
}
}
const char* Options::GetControlIP()
{
if ((m_bRemoteClientMode || m_eClientOperation != opClientNoOperation) &&
!strcmp(m_szControlIP, "0.0.0.0"))
{
return "127.0.0.1";
}
return m_szControlIP;
}
void Options::SetOption(const char* optname, const char* value)
{
OptEntry* pOptEntry = FindOption(optname);
@@ -2071,7 +1989,7 @@ void Options::InitServers()
n++;
}
g_pServerPool->SetTimeout(GetArticleTimeout());
g_pServerPool->SetTimeout(GetConnectionTimeout());
}
void Options::InitCategories()
@@ -2115,7 +2033,7 @@ void Options::InitCategories()
char* szDestDir = NULL;
if (ndestdir && ndestdir[0] != '\0')
{
CheckDir(&szDestDir, destdiroptname, m_szDestDir, false, false);
CheckDir(&szDestDir, destdiroptname, false, false);
}
Category* pCategory = new Category(nname, szDestDir, bUnpack, npostscript);
@@ -2200,7 +2118,8 @@ void Options::InitFeeds()
void Options::InitScheduler()
{
for (int n = 1; ; n++)
int n = 1;
while (true)
{
char optname[128];
@@ -2239,42 +2158,41 @@ void Options::InitScheduler()
break;
}
bool bOK = true;
if (!completed)
{
ConfigError("Task definition not complete for \"Task%i\"", n);
continue;
bOK = false;
}
snprintf(optname, sizeof(optname), "Task%i.Command", n);
optname[sizeof(optname)-1] = '\0';
const char* CommandNames[] = { "pausedownload", "pause", "unpausedownload", "resumedownload", "unpause", "resume",
"pausepostprocess", "unpausepostprocess", "resumepostprocess", "pausepost", "unpausepost", "resumepost",
"downloadrate", "setdownloadrate", "rate", "speed", "script", "process", "pausescan", "unpausescan", "resumescan",
"activateserver", "activateservers", "deactivateserver", "deactivateservers", "fetchfeed", "fetchfeeds" };
const int CommandValues[] = { Scheduler::scPauseDownload, Scheduler::scPauseDownload, Scheduler::scUnpauseDownload,
Scheduler::scUnpauseDownload, Scheduler::scUnpauseDownload, Scheduler::scUnpauseDownload,
Scheduler::scPausePostProcess, Scheduler::scUnpausePostProcess, Scheduler::scUnpausePostProcess,
Scheduler::scPausePostProcess, Scheduler::scUnpausePostProcess, Scheduler::scUnpausePostProcess,
Scheduler::scDownloadRate, Scheduler::scDownloadRate, Scheduler::scDownloadRate, Scheduler::scDownloadRate,
Scheduler::scScript, Scheduler::scProcess, Scheduler::scPauseScan, Scheduler::scUnpauseScan, Scheduler::scUnpauseScan,
Scheduler::scUnpauseDownload, Scheduler::scUnpauseDownload, Scheduler::scUnpauseDownload, Scheduler::scDownloadRate,
Scheduler::scDownloadRate, Scheduler::scDownloadRate, Scheduler::scDownloadRate, Scheduler::scScript,
Scheduler::scProcess, Scheduler::scPauseScan, Scheduler::scUnpauseScan, Scheduler::scUnpauseScan,
Scheduler::scActivateServer, Scheduler::scActivateServer, Scheduler::scDeactivateServer,
Scheduler::scDeactivateServer, Scheduler::scFetchFeed, Scheduler::scFetchFeed };
const int CommandCount = 27;
const int CommandCount = 21;
Scheduler::ECommand eCommand = (Scheduler::ECommand)ParseEnumValue(optname, CommandCount, CommandNames, CommandValues);
if (szParam && strlen(szParam) > 0 && eCommand == Scheduler::scProcess &&
!Util::SplitCommandLine(szParam, NULL))
{
ConfigError("Invalid value for option \"Task%i.Param\"", n);
continue;
bOK = false;
}
int iWeekDays = 0;
if (szWeekDays && !ParseWeekDays(szWeekDays, &iWeekDays))
{
ConfigError("Invalid value for option \"Task%i.WeekDays\": \"%s\"", n, szWeekDays);
continue;
bOK = false;
}
if (eCommand == Scheduler::scDownloadRate)
@@ -2286,13 +2204,13 @@ void Options::InitScheduler()
if (!szErr || *szErr != '\0' || iDownloadRate < 0)
{
ConfigError("Invalid value for option \"Task%i.Param\": \"%s\"", n, szDownloadRate);
continue;
bOK = false;
}
}
else
{
ConfigError("Task definition not complete for \"Task%i\". Option \"Task%i.Param\" is missing", n, n);
continue;
bOK = false;
}
}
@@ -2304,41 +2222,52 @@ void Options::InitScheduler()
Util::EmptyStr(szParam))
{
ConfigError("Task definition not complete for \"Task%i\". Option \"Task%i.Param\" is missing", n, n);
continue;
bOK = false;
}
int iHours, iMinutes;
Tokenizer tok(szTime, ";,");
while (const char* szOneTime = tok.Next())
const char** pTime = &szTime;
while (*pTime)
{
if (!ParseTime(szOneTime, &iHours, &iMinutes))
if (!ParseTime(pTime, &iHours, &iMinutes))
{
ConfigError("Invalid value for option \"Task%i.Time\": \"%s\"", n, szOneTime);
ConfigError("Invalid value for option \"Task%i.Time\": \"%s\"", n, pTime);
break;
}
if (iHours == -1)
if (bOK)
{
for (int iEveryHour = 0; iEveryHour < 24; iEveryHour++)
if (iHours == -1)
{
Scheduler::Task* pTask = new Scheduler::Task(n, iEveryHour, iMinutes, iWeekDays, eCommand, szParam);
for (int iEveryHour = 0; iEveryHour < 24; iEveryHour++)
{
Scheduler::Task* pTask = new Scheduler::Task(n, iEveryHour, iMinutes, iWeekDays, eCommand, szParam);
g_pScheduler->AddTask(pTask);
}
}
else
{
Scheduler::Task* pTask = new Scheduler::Task(n, iHours, iMinutes, iWeekDays, eCommand, szParam);
g_pScheduler->AddTask(pTask);
}
}
else
{
Scheduler::Task* pTask = new Scheduler::Task(n, iHours, iMinutes, iWeekDays, eCommand, szParam);
g_pScheduler->AddTask(pTask);
}
}
n++;
}
}
bool Options::ParseTime(const char* szTime, int* pHours, int* pMinutes)
/*
* Parses Time string and moves current string pointer to the next time token.
*/
bool Options::ParseTime(const char** pTime, int* pHours, int* pMinutes)
{
const char* szTime = *pTime;
const char* szComma = strchr(szTime, ',');
int iColons = 0;
const char* p = szTime;
while (*p)
while (*p && (!szComma || p != szComma))
{
if (!strchr("0123456789: *", *p))
{
@@ -2385,6 +2314,15 @@ bool Options::ParseTime(const char* szTime, int* pHours, int* pMinutes)
return false;
}
if (szComma)
{
*pTime = szComma + 1;
}
else
{
*pTime = NULL;
}
return true;
}
@@ -2657,12 +2595,6 @@ bool Options::ValidateOptionName(const char* optname, const char* optvalue)
return true;
}
if (!strcasecmp(optname, OPTION_CREATELOG) || !strcasecmp(optname, OPTION_RESETLOG))
{
ConfigWarn("Option \"%s\" is obsolete, ignored, use \"%s\" instead", optname, OPTION_WRITELOG);
return true;
}
return false;
}
@@ -2717,19 +2649,6 @@ void Options::ConvertOldOption(char *szOption, int iOptionBufLen, char *szValue,
strncpy(szOption + iNameLen - 10, ".PostScript", iOptionBufLen - 9 /* strlen("Category.") */);
}
if (!strcasecmp(szOption, "WriteBufferSize"))
{
strncpy(szOption, "WriteBuffer", iOptionBufLen);
int val = strtol(szValue, NULL, 10);
val = val == -1 ? 1024 : val / 1024;
snprintf(szValue, iValueBufLen, "%i", val);
}
if (!strcasecmp(szOption, "ConnectionTimeout"))
{
strncpy(szOption, "ArticleTimeout", iOptionBufLen);
}
szOption[iOptionBufLen-1] = '\0';
szOption[iValueBufLen-1] = '\0';
}
@@ -2785,28 +2704,6 @@ void Options::CheckOptions()
m_szConfigTemplate = strdup("");
}
}
if (m_iArticleCache < 0)
{
m_iArticleCache = 0;
}
else if (sizeof(void*) == 4 && m_iArticleCache > 1900)
{
ConfigError("Invalid value for option \"ArticleCache\": %i. Changed to 1900", m_iArticleCache);
m_iArticleCache = 1900;
}
else if (sizeof(void*) == 4 && m_iParBuffer > 1900)
{
ConfigError("Invalid value for option \"ParBuffer\": %i. Changed to 1900", m_iParBuffer);
m_iParBuffer = 1900;
}
if (sizeof(void*) == 4 && m_iParBuffer + m_iArticleCache > 1900)
{
ConfigError("Options \"ArticleCache\" and \"ParBuffer\" in total cannot use more than 1900MB of memory in 32-Bit mode. Changed to 1500 and 400");
m_iArticleCache = 1900;
m_iParBuffer = 400;
}
}
void Options::ParseFileIDList(int argc, char* argv[], int optind)
@@ -3028,7 +2925,7 @@ bool Options::SaveConfig(OptEntries* pOptEntries)
}
// close and truncate the file
int pos = (int)ftell(infile);
int pos = ftell(infile);
fclose(infile);
Util::TruncateFile(m_szConfigFilename, pos);
@@ -3053,13 +2950,12 @@ bool Options::LoadConfigTemplates(ConfigTemplates* pConfigTemplates)
return true;
}
Scripts scriptList;
LoadScripts(&scriptList);
ScriptList scriptList;
LoadScriptList(&scriptList);
const int iBeginSignatureLen = strlen(BEGIN_SCRIPT_SIGNATURE);
const int iQueueEventsSignatureLen = strlen(QUEUE_EVENTS_SIGNATURE);
for (Scripts::iterator it = scriptList.begin(); it != scriptList.end(); it++)
for (ScriptList::iterator it = scriptList.begin(); it != scriptList.end(); it++)
{
Script* pScript = *it;
@@ -3092,9 +2988,7 @@ bool Options::LoadConfigTemplates(ConfigTemplates* pConfigTemplates)
continue;
}
bool bSkip = !strncmp(buf, QUEUE_EVENTS_SIGNATURE, iQueueEventsSignatureLen);
if (bInConfig && !bSkip)
if (bInConfig)
{
stringBuilder.Append(buf);
}
@@ -3112,64 +3006,50 @@ bool Options::LoadConfigTemplates(ConfigTemplates* pConfigTemplates)
return true;
}
void Options::InitConfigTemplates()
{
if (!LoadConfigTemplates(&m_ConfigTemplates))
{
error("Could not read configuration templates");
}
}
void Options::InitScripts()
{
LoadScripts(&m_Scripts);
}
void Options::LoadScripts(Scripts* pScripts)
void Options::LoadScriptList(ScriptList* pScriptList)
{
if (strlen(m_szScriptDir) == 0)
{
return;
}
Scripts tmpScripts;
LoadScriptDir(&tmpScripts, m_szScriptDir, false);
tmpScripts.sort(CompareScripts);
ScriptList tmpScriptList;
LoadScriptDir(&tmpScriptList, m_szScriptDir, false);
tmpScriptList.sort(CompareScripts);
// first add all scripts from m_szScriptOrder
Tokenizer tok(m_szScriptOrder, ",;");
while (const char* szScriptName = tok.Next())
{
Script* pScript = tmpScripts.Find(szScriptName);
Script* pScript = tmpScriptList.Find(szScriptName);
if (pScript)
{
tmpScripts.remove(pScript);
pScripts->push_back(pScript);
tmpScriptList.remove(pScript);
pScriptList->push_back(pScript);
}
}
// second add all other scripts from scripts directory
for (Scripts::iterator it = tmpScripts.begin(); it != tmpScripts.end(); it++)
for (ScriptList::iterator it = tmpScriptList.begin(); it != tmpScriptList.end(); it++)
{
Script* pScript = *it;
if (!pScripts->Find(pScript->GetName()))
if (!pScriptList->Find(pScript->GetName()))
{
pScripts->push_back(pScript);
pScriptList->push_back(pScript);
}
}
tmpScripts.clear();
tmpScriptList.clear();
BuildScriptDisplayNames(pScripts);
BuildScriptDisplayNames(pScriptList);
}
void Options::LoadScriptDir(Scripts* pScripts, const char* szDirectory, bool bIsSubDir)
void Options::LoadScriptDir(ScriptList* pScriptList, const char* szDirectory, bool bIsSubDir)
{
int iBufSize = 1024*10;
char* szBuffer = (char*)malloc(iBufSize+1);
const int iBeginSignatureLen = strlen(BEGIN_SCRIPT_SIGNATURE);
const int iQueueEventsSignatureLen = strlen(QUEUE_EVENTS_SIGNATURE);
DirBrowser dir(szDirectory);
while (const char* szFilename = dir.Next())
@@ -3225,26 +3105,12 @@ void Options::LoadScriptDir(Scripts* pScripts, const char* szDirectory, bool bIs
}
szScriptName[1024-1] = '\0';
char* szQueueEvents = NULL;
if (bQueueScript)
{
while (char* szLine = tok.Next())
{
if (!strncmp(szLine, QUEUE_EVENTS_SIGNATURE, iQueueEventsSignatureLen))
{
szQueueEvents = szLine + iQueueEventsSignatureLen;
break;
}
}
}
Script* pScript = new Script(szScriptName, szFullFilename);
pScript->SetPostScript(bPostScript);
pScript->SetScanScript(bScanScript);
pScript->SetQueueScript(bQueueScript);
pScript->SetSchedulerScript(bSchedulerScript);
pScript->SetQueueEvents(szQueueEvents);
pScripts->push_back(pScript);
pScriptList->push_back(pScript);
break;
}
}
@@ -3256,7 +3122,7 @@ void Options::LoadScriptDir(Scripts* pScripts, const char* szDirectory, bool bIs
snprintf(szFullFilename, 1024, "%s%s%c", szDirectory, szFilename, PATH_SEPARATOR);
szFullFilename[1024-1] = '\0';
LoadScriptDir(pScripts, szFullFilename, true);
LoadScriptDir(pScriptList, szFullFilename, true);
}
}
}
@@ -3269,12 +3135,12 @@ bool Options::CompareScripts(Script* pScript1, Script* pScript2)
return strcmp(pScript1->GetName(), pScript2->GetName()) < 0;
}
void Options::BuildScriptDisplayNames(Scripts* pScripts)
void Options::BuildScriptDisplayNames(ScriptList* pScriptList)
{
// trying to use short name without path and extension.
// if there are other scripts with the same short name - using a longer name instead (with ot without extension)
for (Scripts::iterator it = pScripts->begin(); it != pScripts->end(); it++)
for (ScriptList::iterator it = pScriptList->begin(); it != pScriptList->end(); it++)
{
Script* pScript = *it;
@@ -3285,7 +3151,7 @@ void Options::BuildScriptDisplayNames(Scripts* pScripts)
const char* szDisplayName = Util::BaseFileName(szShortName);
for (Scripts::iterator it2 = pScripts->begin(); it2 != pScripts->end(); it2++)
for (ScriptList::iterator it2 = pScriptList->begin(); it2 != pScriptList->end(); it2++)
{
Script* pScript2 = *it2;

View File

@@ -64,13 +64,6 @@ public:
opClientRequestHistory,
opClientRequestDownloadUrl
};
enum EWriteLog
{
wlNone,
wlAppend,
wlReset,
wlRotate
};
enum EMessageTarget
{
mtNone,
@@ -183,7 +176,6 @@ public:
bool m_bScanScript;
bool m_bQueueScript;
bool m_bSchedulerScript;
char* m_szQueueEvents;
public:
Script(const char* szName, const char* szLocation);
@@ -200,17 +192,14 @@ public:
void SetQueueScript(bool bQueueScript) { m_bQueueScript = bQueueScript; }
bool GetSchedulerScript() { return m_bSchedulerScript; }
void SetSchedulerScript(bool bSchedulerScript) { m_bSchedulerScript = bSchedulerScript; }
void SetQueueEvents(const char* szQueueEvents);
const char* GetQueueEvents() { return m_szQueueEvents; }
};
typedef std::list<Script*> ScriptsBase;
typedef std::list<Script*> ScriptListBase;
class Scripts: public ScriptsBase
class ScriptList: public ScriptListBase
{
public:
~Scripts();
void Clear();
~ScriptList();
Script* Find(const char* szName);
};
@@ -242,8 +231,6 @@ private:
bool m_bConfigInitialized;
Mutex m_mutexOptEntries;
Categories m_Categories;
Scripts m_Scripts;
ConfigTemplates m_ConfigTemplates;
// Options
bool m_bConfigErrors;
@@ -264,8 +251,8 @@ private:
EMessageTarget m_eDetailTarget;
bool m_bDecode;
bool m_bCreateBrokenLog;
int m_iArticleTimeout;
int m_iUrlTimeout;
bool m_bResetLog;
int m_iConnectionTimeout;
int m_iTerminateTimeout;
bool m_bAppendCategoryDir;
bool m_bContinuePartial;
@@ -288,16 +275,12 @@ private:
bool m_bReloadQueue;
int m_iUrlConnections;
int m_iLogBufferSize;
EWriteLog m_eWriteLog;
int m_iRotateLog;
bool m_bCreateLog;
char* m_szLogFile;
EParCheck m_eParCheck;
bool m_bParRepair;
EParScan m_eParScan;
bool m_bParQuick;
bool m_bParRename;
int m_iParBuffer;
int m_iParThreads;
EHealthCheck m_eHealthCheck;
char* m_szPostScript;
char* m_szScriptOrder;
@@ -311,7 +294,7 @@ private:
bool m_bCursesGroup;
bool m_bCrcCheck;
bool m_bDirectWrite;
int m_iWriteBuffer;
int m_iWriteBufferSize;
int m_iNzbDirInterval;
int m_iNzbDirFileAge;
bool m_bParCleanupQueue;
@@ -336,8 +319,6 @@ private:
bool m_bUrlForce;
int m_iTimeCorrection;
int m_iPropagationDelay;
int m_iArticleCache;
int m_iEventInterval;
// Parsed command-line parameters
bool m_bServerMode;
@@ -382,8 +363,6 @@ private:
void InitCategories();
void InitScheduler();
void InitFeeds();
void InitScripts();
void InitConfigTemplates();
void CheckOptions();
void PrintUsage(char* com);
void Dump();
@@ -397,20 +376,18 @@ private:
bool SplitOptionString(const char* option, char** pOptName, char** pOptValue);
bool ValidateOptionName(const char* optname, const char* optvalue);
void LoadConfigFile();
void CheckDir(char** dir, const char* szOptionName, const char* szParentDir,
bool bAllowEmpty, bool bCreate);
void CheckDir(char** dir, const char* szOptionName, bool bAllowEmpty, bool bCreate);
void ParseFileIDList(int argc, char* argv[], int optind);
void ParseFileNameList(int argc, char* argv[], int optind);
bool ParseTime(const char* szTime, int* pHours, int* pMinutes);
bool ParseTime(const char** pTime, int* pHours, int* pMinutes);
bool ParseWeekDays(const char* szWeekDays, int* pWeekDaysBits);
void ConfigError(const char* msg, ...);
void ConfigWarn(const char* msg, ...);
void LocateOptionSrcPos(const char *szOptionName);
void ConvertOldOption(char *szOption, int iOptionBufLen, char *szValue, int iValueBufLen);
static bool CompareScripts(Script* pScript1, Script* pScript2);
void LoadScriptDir(Scripts* pScripts, const char* szDirectory, bool bIsSubDir);
void BuildScriptDisplayNames(Scripts* pScripts);
void LoadScripts(Scripts* pScripts);
void LoadScriptDir(ScriptList* pScriptList, const char* szDirectory, bool bIsSubDir);
void BuildScriptDisplayNames(ScriptList* pScriptList);
public:
Options(int argc, char* argv[]);
@@ -419,8 +396,7 @@ public:
bool LoadConfig(OptEntries* pOptEntries);
bool SaveConfig(OptEntries* pOptEntries);
bool LoadConfigTemplates(ConfigTemplates* pConfigTemplates);
Scripts* GetScripts() { return &m_Scripts; }
ConfigTemplates* GetConfigTemplates() { return &m_ConfigTemplates; }
void LoadScriptList(ScriptList* pScriptList);
// Options
OptEntries* LockOptEntries();
@@ -435,13 +411,13 @@ public:
const char* GetConfigTemplate() { return m_szConfigTemplate; }
const char* GetScriptDir() { return m_szScriptDir; }
bool GetCreateBrokenLog() const { return m_bCreateBrokenLog; }
bool GetResetLog() const { return m_bResetLog; }
EMessageTarget GetInfoTarget() const { return m_eInfoTarget; }
EMessageTarget GetWarningTarget() const { return m_eWarningTarget; }
EMessageTarget GetErrorTarget() const { return m_eErrorTarget; }
EMessageTarget GetDebugTarget() const { return m_eDebugTarget; }
EMessageTarget GetDetailTarget() const { return m_eDetailTarget; }
int GetArticleTimeout() { return m_iArticleTimeout; }
int GetUrlTimeout() { return m_iUrlTimeout; }
int GetConnectionTimeout() { return m_iConnectionTimeout; }
int GetTerminateTimeout() { return m_iTerminateTimeout; }
bool GetDecode() { return m_bDecode; };
bool GetAppendCategoryDir() { return m_bAppendCategoryDir; }
@@ -450,7 +426,7 @@ public:
int GetRetryInterval() { return m_iRetryInterval; }
bool GetSaveQueue() { return m_bSaveQueue; }
bool GetDupeCheck() { return m_bDupeCheck; }
const char* GetControlIP();
const char* GetControlIP() { return m_szControlIP; }
const char* GetControlUsername() { return m_szControlUsername; }
const char* GetControlPassword() { return m_szControlPassword; }
int GetControlPort() { return m_iControlPort; }
@@ -465,16 +441,12 @@ public:
bool GetReloadQueue() { return m_bReloadQueue; }
int GetUrlConnections() { return m_iUrlConnections; }
int GetLogBufferSize() { return m_iLogBufferSize; }
EWriteLog GetWriteLog() { return m_eWriteLog; }
bool GetCreateLog() { return m_bCreateLog; }
const char* GetLogFile() { return m_szLogFile; }
int GetRotateLog() { return m_iRotateLog; }
EParCheck GetParCheck() { return m_eParCheck; }
bool GetParRepair() { return m_bParRepair; }
EParScan GetParScan() { return m_eParScan; }
bool GetParQuick() { return m_bParQuick; }
bool GetParRename() { return m_bParRename; }
int GetParBuffer() { return m_iParBuffer; }
int GetParThreads() { return m_iParThreads; }
EHealthCheck GetHealthCheck() { return m_eHealthCheck; }
const char* GetScriptOrder() { return m_szScriptOrder; }
const char* GetPostScript() { return m_szPostScript; }
@@ -487,7 +459,7 @@ public:
bool GetCursesGroup() { return m_bCursesGroup; }
bool GetCrcCheck() { return m_bCrcCheck; }
bool GetDirectWrite() { return m_bDirectWrite; }
int GetWriteBuffer() { return m_iWriteBuffer; }
int GetWriteBufferSize() { return m_iWriteBufferSize; }
int GetNzbDirInterval() { return m_iNzbDirInterval; }
int GetNzbDirFileAge() { return m_iNzbDirFileAge; }
bool GetParCleanupQueue() { return m_bParCleanupQueue; }
@@ -512,8 +484,6 @@ public:
bool GetUrlForce() { return m_bUrlForce; }
int GetTimeCorrection() { return m_iTimeCorrection; }
int GetPropagationDelay() { return m_iPropagationDelay; }
int GetArticleCache() { return m_iArticleCache; }
int GetEventInterval() { return m_iEventInterval; }
Category* FindCategory(const char* szName, bool bSearchAliases) { return m_Categories.FindCategory(szName, bSearchAliases); }

View File

@@ -125,11 +125,16 @@ void Scheduler::FirstCheck()
m_mutexTaskList.Unlock();
// check all tasks for the last week
time_t tCurrent = time(NULL);
m_tLastCheck = tCurrent - 60*60*24*7;
m_bDetectClockChanges = false;
m_bExecuteProcess = false;
CheckTasks();
}
void Scheduler::IntervalCheck()
{
m_bDetectClockChanges = true;
m_bExecuteProcess = true;
CheckTasks();
CheckScheduledResume();
@@ -145,20 +150,21 @@ void Scheduler::CheckTasks()
if (!m_TaskList.empty())
{
// Detect large step changes of system time
time_t tDiff = tCurrent - m_tLastCheck;
if (tDiff > 60*90 || tDiff < 0)
if (m_bDetectClockChanges)
{
debug("Reset scheduled tasks (detected clock change greater than 90 minutes or negative)");
// check all tasks for the last week
m_tLastCheck = tCurrent - 60*60*24*7;
m_bExecuteProcess = false;
for (TaskList::iterator it = m_TaskList.begin(); it != m_TaskList.end(); it++)
// Detect large step changes of system time
time_t tDiff = tCurrent - m_tLastCheck;
if (tDiff > 60*90 || tDiff < -60*90)
{
Task* pTask = *it;
pTask->m_tLastExecuted = 0;
debug("Reset scheduled tasks (detected clock adjustment greater than 90 minutes)");
m_bExecuteProcess = false;
m_tLastCheck = tCurrent;
for (TaskList::iterator it = m_TaskList.begin(); it != m_TaskList.end(); it++)
{
Task* pTask = *it;
pTask->m_tLastExecuted = 0;
}
}
}
@@ -224,8 +230,7 @@ void Scheduler::CheckTasks()
void Scheduler::ExecuteTask(Task* pTask)
{
const char* szCommandName[] = { "Pause", "Unpause", "Pause Post-processing", "Unpause Post-processing",
"Set download rate", "Execute process", "Execute script",
const char* szCommandName[] = { "Pause", "Unpause", "Set download rate", "Execute process", "Execute script",
"Pause Scan", "Unpause Scan", "Enable Server", "Disable Server", "Fetch Feed" };
debug("Executing scheduled command: %s", szCommandName[pTask->m_eCommand]);
@@ -245,18 +250,6 @@ void Scheduler::ExecuteTask(Task* pTask)
m_bPauseDownloadChanged = true;
break;
case scPausePostProcess:
case scUnpausePostProcess:
g_pOptions->SetPausePostProcess(pTask->m_eCommand == scPausePostProcess);
m_bPausePostProcessChanged = true;
break;
case scPauseScan:
case scUnpauseScan:
g_pOptions->SetPauseScan(pTask->m_eCommand == scPauseScan);
m_bPauseScanChanged = true;
break;
case scScript:
case scProcess:
if (m_bExecuteProcess)
@@ -265,6 +258,12 @@ void Scheduler::ExecuteTask(Task* pTask)
}
break;
case scPauseScan:
case scUnpauseScan:
g_pOptions->SetPauseScan(pTask->m_eCommand == scPauseScan);
m_bPauseScanChanged = true;
break;
case scActivateServer:
case scDeactivateServer:
EditServer(pTask->m_eCommand == scActivateServer, pTask->m_szParam);
@@ -283,7 +282,6 @@ void Scheduler::PrepareLog()
{
m_bDownloadRateChanged = false;
m_bPauseDownloadChanged = false;
m_bPausePostProcessChanged = false;
m_bPauseScanChanged = false;
m_bServerChanged = false;
}
@@ -298,10 +296,6 @@ void Scheduler::PrintLog()
{
info("Scheduler: %s download", g_pOptions->GetPauseDownload() ? "pausing" : "unpausing");
}
if (m_bPausePostProcessChanged)
{
info("Scheduler: %s post-processing", g_pOptions->GetPausePostProcess() ? "pausing" : "unpausing");
}
if (m_bPauseScanChanged)
{
info("Scheduler: %s scan", g_pOptions->GetPauseScan() ? "pausing" : "unpausing");

View File

@@ -39,8 +39,6 @@ public:
{
scPauseDownload,
scUnpauseDownload,
scPausePostProcess,
scUnpausePostProcess,
scDownloadRate,
scScript,
scProcess,
@@ -77,10 +75,10 @@ private:
TaskList m_TaskList;
Mutex m_mutexTaskList;
time_t m_tLastCheck;
bool m_bDetectClockChanges;
bool m_bDownloadRateChanged;
bool m_bExecuteProcess;
bool m_bPauseDownloadChanged;
bool m_bPausePostProcessChanged;
bool m_bPauseScanChanged;
bool m_bServerChanged;
ServerStatusList m_ServerStatusList;

View File

@@ -1,321 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WIN32
#include "win32.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef WIN32
#include <dbghelp.h>
#else
#include <unistd.h>
#include <sys/resource.h>
#include <signal.h>
#endif
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
#ifdef HAVE_BACKTRACE
#include <execinfo.h>
#endif
#include "nzbget.h"
#include "Log.h"
#include "Options.h"
#include "StackTrace.h"
extern Options* g_pOptions;
extern void ExitProc();
#ifdef WIN32
#ifdef DEBUG
void PrintBacktrace(PCONTEXT pContext)
{
HANDLE hProcess = GetCurrentProcess();
HANDLE hThread = GetCurrentThread();
char szAppDir[MAX_PATH + 1];
GetModuleFileName(NULL, szAppDir, sizeof(szAppDir));
char* end = strrchr(szAppDir, PATH_SEPARATOR);
if (end) *end = '\0';
SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS);
if (!SymInitialize(hProcess, szAppDir, TRUE))
{
warn("Could not obtain detailed exception information: SymInitialize failed");
return;
}
const int MAX_NAMELEN = 1024;
IMAGEHLP_SYMBOL64* pSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_NAMELEN);
memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + MAX_NAMELEN);
pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
pSym->MaxNameLength = MAX_NAMELEN;
IMAGEHLP_LINE64 ilLine;
memset(&ilLine, 0, sizeof(ilLine));
ilLine.SizeOfStruct = sizeof(ilLine);
STACKFRAME64 sfStackFrame;
memset(&sfStackFrame, 0, sizeof(sfStackFrame));
DWORD imageType;
#ifdef _M_IX86
imageType = IMAGE_FILE_MACHINE_I386;
sfStackFrame.AddrPC.Offset = pContext->Eip;
sfStackFrame.AddrPC.Mode = AddrModeFlat;
sfStackFrame.AddrFrame.Offset = pContext->Ebp;
sfStackFrame.AddrFrame.Mode = AddrModeFlat;
sfStackFrame.AddrStack.Offset = pContext->Esp;
sfStackFrame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
imageType = IMAGE_FILE_MACHINE_AMD64;
sfStackFrame.AddrPC.Offset = pContext->Rip;
sfStackFrame.AddrPC.Mode = AddrModeFlat;
sfStackFrame.AddrFrame.Offset = pContext->Rsp;
sfStackFrame.AddrFrame.Mode = AddrModeFlat;
sfStackFrame.AddrStack.Offset = pContext->Rsp;
sfStackFrame.AddrStack.Mode = AddrModeFlat;
#else
warn("Could not obtain detailed exception information: platform not supported");
return;
#endif
for (int frameNum = 0; ; frameNum++)
{
if (frameNum > 1000)
{
warn("Endless stack, abort tracing");
return;
}
if (!StackWalk64(imageType, hProcess, hThread, &sfStackFrame, pContext, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
{
warn("Could not obtain detailed exception information: StackWalk64 failed");
return;
}
DWORD64 dwAddr = sfStackFrame.AddrPC.Offset;
char szSymName[1024];
char szSrcFileName[1024];
int iLineNumber = 0;
DWORD64 dwSymbolDisplacement;
if (SymGetSymFromAddr64(hProcess, dwAddr, &dwSymbolDisplacement, pSym))
{
UnDecorateSymbolName(pSym->Name, szSymName, sizeof(szSymName), UNDNAME_COMPLETE);
szSymName[sizeof(szSymName) - 1] = '\0';
}
else
{
strncpy(szSymName, "<symbol not available>", sizeof(szSymName));
}
DWORD dwLineDisplacement;
if (SymGetLineFromAddr64(hProcess, dwAddr, &dwLineDisplacement, &ilLine))
{
iLineNumber = ilLine.LineNumber;
char* szUseFileName = ilLine.FileName;
char* szRoot = strstr(szUseFileName, "\\daemon\\");
if (szRoot)
{
szUseFileName = szRoot;
}
strncpy(szSrcFileName, szUseFileName, sizeof(szSrcFileName));
szSrcFileName[sizeof(szSrcFileName) - 1] = '\0';
}
else
{
strncpy(szSrcFileName, "<filename not available>", sizeof(szSymName));
}
info("%s (%i) : %s", szSrcFileName, iLineNumber, szSymName);
if (sfStackFrame.AddrReturn.Offset == 0)
{
break;
}
}
}
#endif
LONG __stdcall ExceptionFilter(EXCEPTION_POINTERS* pExPtrs)
{
error("Unhandled Exception: code: 0x%8.8X, flags: %d, address: 0x%8.8X",
pExPtrs->ExceptionRecord->ExceptionCode,
pExPtrs->ExceptionRecord->ExceptionFlags,
pExPtrs->ExceptionRecord->ExceptionAddress);
#ifdef DEBUG
PrintBacktrace(pExPtrs->ContextRecord);
#else
info("Detailed exception information can be printed by debug version of NZBGet (available from download page)");
#endif
ExitProcess(-1);
return EXCEPTION_CONTINUE_SEARCH;
}
void InstallErrorHandler()
{
SetUnhandledExceptionFilter(ExceptionFilter);
}
#else
#ifdef DEBUG
typedef void(*sighandler)(int);
std::vector<sighandler> SignalProcList;
#endif
#ifdef HAVE_SYS_PRCTL_H
/**
* activates the creation of core-files
*/
void EnableDumpCore()
{
rlimit rlim;
rlim.rlim_cur= RLIM_INFINITY;
rlim.rlim_max= RLIM_INFINITY;
setrlimit(RLIMIT_CORE, &rlim);
prctl(PR_SET_DUMPABLE, 1);
}
#endif
void PrintBacktrace()
{
#ifdef HAVE_BACKTRACE
printf("Segmentation fault, tracing...\n");
void *array[100];
size_t size;
char **strings;
size_t i;
size = backtrace(array, 100);
strings = backtrace_symbols(array, size);
// first trace to screen
printf("Obtained %zd stack frames\n", size);
for (i = 0; i < size; i++)
{
printf("%s\n", strings[i]);
}
// then trace to log
error("Segmentation fault, tracing...");
error("Obtained %zd stack frames", size);
for (i = 0; i < size; i++)
{
error("%s", strings[i]);
}
free(strings);
#else
error("Segmentation fault");
#endif
}
/*
* Signal handler
*/
void SignalProc(int iSignal)
{
switch (iSignal)
{
case SIGINT:
signal(SIGINT, SIG_DFL); // Reset the signal handler
ExitProc();
break;
case SIGTERM:
signal(SIGTERM, SIG_DFL); // Reset the signal handler
ExitProc();
break;
case SIGCHLD:
// ignoring
break;
#ifdef DEBUG
case SIGSEGV:
signal(SIGSEGV, SIG_DFL); // Reset the signal handler
PrintBacktrace();
break;
#endif
}
}
void InstallErrorHandler()
{
#ifdef HAVE_SYS_PRCTL_H
if (g_pOptions->GetDumpCore())
{
EnableDumpCore();
}
#endif
signal(SIGINT, SignalProc);
signal(SIGTERM, SignalProc);
signal(SIGPIPE, SIG_IGN);
#ifdef DEBUG
signal(SIGSEGV, SignalProc);
#endif
#ifdef SIGCHLD_HANDLER
// it could be necessary on some systems to activate a handler for SIGCHLD
// however it make troubles on other systems and is deactivated by default
signal(SIGCHLD, SignalProc);
#endif
}
#endif
#ifdef DEBUG
class SegFault
{
public:
void DoSegFault()
{
char* N = NULL;
strcpy(N, "");
}
};
void TestSegFault()
{
SegFault s;
s.DoSegFault();
}
#endif

View File

@@ -1,35 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef STACKTRACE_H
#define STACKTRACE_H
void InstallErrorHandler();
#ifdef DEBUG
void TestSegFault();
#endif
#endif

View File

@@ -40,6 +40,7 @@
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <sys/resource.h>
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
@@ -52,6 +53,9 @@
#ifndef DISABLE_PARCHECK
#include <iostream>
#endif
#ifdef HAVE_BACKTRACE
#include <execinfo.h>
#endif
#include "nzbget.h"
#include "ServerPool.h"
@@ -75,11 +79,8 @@
#include "Scanner.h"
#include "FeedCoordinator.h"
#include "Maintenance.h"
#include "ArticleWriter.h"
#include "StatMeter.h"
#include "QueueScript.h"
#include "Util.h"
#include "StackTrace.h"
#ifdef WIN32
#include "NTService.h"
#endif
@@ -91,7 +92,15 @@ void Reload();
void Cleanup();
void ProcessClientRequest();
#ifndef WIN32
void InstallSignalHandlers();
void Daemonize();
void PrintBacktrace();
#ifdef HAVE_SYS_PRCTL_H
void EnableDumpCore();
#endif
#ifdef DEBUG
void MakeSegFault();
#endif
#endif
#ifndef DISABLE_PARCHECK
void DisableCout();
@@ -114,8 +123,6 @@ Scheduler* g_pScheduler = NULL;
Scanner* g_pScanner = NULL;
FeedCoordinator* g_pFeedCoordinator = NULL;
Maintenance* g_pMaintenance = NULL;
ArticleCache* g_pArticleCache = NULL;
QueueScriptCoordinator* g_pQueueScriptCoordinator = NULL;
int g_iArgumentCount;
char* (*g_szEnvironmentVariables)[] = NULL;
char* (*g_szArguments)[] = NULL;
@@ -130,7 +137,7 @@ int main(int argc, char *argv[], char *argp[])
#ifdef _DEBUG
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF
#ifdef DEBUG_CRTMEMLEAKS
| _CRTDBG_CHECK_CRT_DF | _CRTDBG_CHECK_ALWAYS_DF
#endif
@@ -167,6 +174,12 @@ int main(int argc, char *argv[], char *argp[])
RunMain();
#ifdef WIN32
#ifdef _DEBUG
_CrtDumpMemoryLeaks();
#endif
#endif
return 0;
}
@@ -210,9 +223,7 @@ void Run(bool bReload)
g_pDupeCoordinator = new DupeCoordinator();
g_pUrlCoordinator = new UrlCoordinator();
g_pFeedCoordinator = new FeedCoordinator();
g_pArticleCache = new ArticleCache();
g_pMaintenance = new Maintenance();
g_pQueueScriptCoordinator = new QueueScriptCoordinator();
debug("Reading options");
g_pOptions = new Options(g_iArgumentCount, *g_szArguments);
@@ -225,9 +236,14 @@ void Run(bool bReload)
}
#endif
if (g_pOptions->GetServerMode() && g_pOptions->GetCreateLog() && g_pOptions->GetResetLog())
{
debug("Deleting old log-file");
g_pLog->ResetLog();
}
g_pLog->InitOptions();
g_pScanner->InitOptions();
g_pQueueScriptCoordinator->InitOptions();
if (g_pOptions->GetDaemonMode())
{
@@ -261,13 +277,23 @@ void Run(bool bReload)
g_pStatMeter->Init();
}
InstallErrorHandler();
#ifndef WIN32
#ifdef HAVE_SYS_PRCTL_H
if (g_pOptions->GetDumpCore())
{
EnableDumpCore();
}
#endif
#endif
#ifndef WIN32
InstallSignalHandlers();
#ifdef DEBUG
if (g_pOptions->GetTestBacktrace())
{
TestSegFault();
MakeSegFault();
}
#endif
#endif
// client request
@@ -329,7 +355,7 @@ void Run(bool bReload)
abort("FATAL ERROR: Parsing NZB-document %s failed\n\n", g_pOptions->GetArgFilename() ? g_pOptions->GetArgFilename() : "N/A");
return;
}
g_pScanner->InitPPParameters(szCategory, pNZBFile->GetNZBInfo()->GetParameters(), false);
g_pScanner->InitPPParameters(szCategory, pNZBFile->GetNZBInfo()->GetParameters());
g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, NULL, false);
delete pNZBFile;
}
@@ -343,17 +369,12 @@ void Run(bool bReload)
g_pUrlCoordinator->Start();
g_pPrePostProcessor->Start();
g_pFeedCoordinator->Start();
if (g_pOptions->GetArticleCache() > 0)
{
g_pArticleCache->Start();
}
// enter main program-loop
while (g_pQueueCoordinator->IsRunning() ||
g_pUrlCoordinator->IsRunning() ||
g_pPrePostProcessor->IsRunning() ||
g_pFeedCoordinator->IsRunning() ||
g_pArticleCache->IsRunning())
g_pFeedCoordinator->IsRunning())
{
if (!g_pOptions->GetServerMode() &&
!g_pQueueCoordinator->HasMoreJobs() &&
@@ -377,10 +398,6 @@ void Run(bool bReload)
{
g_pFeedCoordinator->Stop();
}
if (!g_pArticleCache->IsStopped())
{
g_pArticleCache->Stop();
}
}
usleep(100 * 1000);
}
@@ -390,11 +407,8 @@ void Run(bool bReload)
debug("UrlCoordinator stopped");
debug("PrePostProcessor stopped");
debug("FeedCoordinator stopped");
debug("ArticleCache stopped");
}
ScriptController::TerminateAll();
// Stop network-server
if (g_pRemoteServer)
{
@@ -581,7 +595,6 @@ void ExitProc()
g_pUrlCoordinator->Stop();
g_pPrePostProcessor->Stop();
g_pFeedCoordinator->Stop();
g_pArticleCache->Stop();
}
}
}
@@ -593,6 +606,114 @@ void Reload()
ExitProc();
}
#ifndef WIN32
#ifdef DEBUG
typedef void(*sighandler)(int);
std::vector<sighandler> SignalProcList;
#endif
/*
* Signal handler
*/
void SignalProc(int iSignal)
{
switch (iSignal)
{
case SIGINT:
signal(SIGINT, SIG_DFL); // Reset the signal handler
ExitProc();
break;
case SIGTERM:
signal(SIGTERM, SIG_DFL); // Reset the signal handler
ExitProc();
break;
case SIGCHLD:
// ignoring
break;
#ifdef DEBUG
case SIGSEGV:
signal(SIGSEGV, SIG_DFL); // Reset the signal handler
PrintBacktrace();
break;
#endif
}
}
void InstallSignalHandlers()
{
signal(SIGINT, SignalProc);
signal(SIGTERM, SignalProc);
signal(SIGPIPE, SIG_IGN);
#ifdef DEBUG
signal(SIGSEGV, SignalProc);
#endif
#ifdef SIGCHLD_HANDLER
// it could be necessary on some systems to activate a handler for SIGCHLD
// however it make troubles on other systems and is deactivated by default
signal(SIGCHLD, SignalProc);
#endif
}
void PrintBacktrace()
{
#ifdef HAVE_BACKTRACE
printf("Segmentation fault, tracing...\n");
void *array[100];
size_t size;
char **strings;
size_t i;
size = backtrace(array, 100);
strings = backtrace_symbols(array, size);
// first trace to screen
printf("Obtained %zd stack frames\n", size);
for (i = 0; i < size; i++)
{
printf("%s\n", strings[i]);
}
// then trace to log
error("Segmentation fault, tracing...");
error("Obtained %zd stack frames", size);
for (i = 0; i < size; i++)
{
error("%s", strings[i]);
}
free(strings);
#else
error("Segmentation fault");
#endif
}
#ifdef DEBUG
void MakeSegFault()
{
char* N = NULL;
strcpy(N, "");
}
#endif
#ifdef HAVE_SYS_PRCTL_H
/**
* activates the creation of core-files
*/
void EnableDumpCore()
{
rlimit rlim;
rlim.rlim_cur= RLIM_INFINITY;
rlim.rlim_max= RLIM_INFINITY;
setrlimit(RLIMIT_CORE, &rlim);
prctl(PR_SET_DUMPABLE, 1);
}
#endif
#endif
void Cleanup()
{
debug("Cleaning up global objects");
@@ -672,16 +793,6 @@ void Cleanup()
g_pFeedCoordinator = NULL;
debug("FeedCoordinator deleted");
debug("Deleting ArticleCache");
delete g_pArticleCache;
g_pArticleCache = NULL;
debug("ArticleCache deleted");
debug("Deleting QueueScriptCoordinator");
delete g_pQueueScriptCoordinator;
g_pQueueScriptCoordinator = NULL;
debug("QueueScriptCoordinator deleted");
debug("Deleting Maintenance");
delete g_pMaintenance;
g_pMaintenance = NULL;

View File

@@ -50,6 +50,7 @@
#define S_ISREG(mode) __S_ISTYPE((mode), _S_IFREG)
#define S_DIRMODE NULL
#define usleep(usec) Sleep((usec) / 1000)
#define gettimeofday(tm, ignore) _ftime(tm)
#define socklen_t int
#define SHUT_WR 0x01
#define SHUT_RDWR 0x02
@@ -58,8 +59,6 @@
#define LINE_ENDING "\r\n"
#define pid_t int
#define atoll _atoi64
#define fseek _fseeki64
#define ftell _ftelli64
#ifndef FSCTL_SET_SPARSE
#define FSCTL_SET_SPARSE 590020
#endif

View File

@@ -46,7 +46,6 @@
#include "nzbget.h"
#include "ArticleDownloader.h"
#include "ArticleWriter.h"
#include "Decoder.h"
#include "Log.h"
#include "Options.h"
@@ -62,14 +61,15 @@ ArticleDownloader::ArticleDownloader()
{
debug("Creating ArticleDownloader");
m_szResultFilename = NULL;
m_szTempFilename = NULL;
m_szArticleFilename = NULL;
m_szInfoName = NULL;
m_szConnectionName[0] = '\0';
m_szOutputFilename = NULL;
m_pConnection = NULL;
m_eStatus = adUndefined;
m_bDuplicate = false;
m_eFormat = Decoder::efUnknown;
m_szArticleFilename = NULL;
m_iDownloadedSize = 0;
m_ArticleWriter.SetOwner(this);
SetLastUpdateTimeNow();
}
@@ -77,14 +77,25 @@ ArticleDownloader::~ArticleDownloader()
{
debug("Destroying ArticleDownloader");
free(m_szInfoName);
free(m_szTempFilename);
free(m_szArticleFilename);
free(m_szInfoName);
free(m_szOutputFilename);
}
void ArticleDownloader::SetInfoName(const char* szInfoName)
void ArticleDownloader::SetTempFilename(const char* v)
{
m_szInfoName = strdup(szInfoName);
m_ArticleWriter.SetInfoName(m_szInfoName);
m_szTempFilename = strdup(v);
}
void ArticleDownloader::SetOutputFilename(const char* v)
{
m_szOutputFilename = strdup(v);
}
void ArticleDownloader::SetInfoName(const char * v)
{
m_szInfoName = strdup(v);
}
/*
@@ -114,10 +125,9 @@ void ArticleDownloader::Run()
SetStatus(adRunning);
m_ArticleWriter.SetFileInfo(m_pFileInfo);
m_ArticleWriter.SetArticleInfo(m_pArticleInfo);
m_ArticleWriter.Prepare();
BuildOutputFilename();
m_szResultFilename = m_pArticleInfo->GetResultFilename();
EStatus Status = adFailed;
int iRetries = g_pOptions->GetRetries() > 0 ? g_pOptions->GetRetries() : 1;
int iRemainedRetries = iRetries;
@@ -154,16 +164,12 @@ void ArticleDownloader::Run()
m_pConnection->SetSuppressErrors(false);
snprintf(m_szConnectionName, sizeof(m_szConnectionName), "%s (%s)",
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost());
m_szConnectionName[sizeof(m_szConnectionName) - 1] = '\0';
// test connection
bool bConnected = m_pConnection && m_pConnection->Connect();
if (bConnected && !IsStopped())
{
NewsServer* pNewsServer = m_pConnection->GetNewsServer();
detail("Downloading %s @ %s", m_szInfoName, m_szConnectionName);
detail("Downloading %s @ %s (%s)", m_szInfoName, pNewsServer->GetName(), m_pConnection->GetHost());
Status = Download();
@@ -195,7 +201,7 @@ void ArticleDownloader::Run()
if (m_pConnection)
{
AddServerData();
g_pStatMeter->AddServerData(m_pConnection->FetchTotalBytesRead(), m_pConnection->GetNewsServer()->GetID());
}
if (Status == adFinished || Status == adFatalError)
@@ -300,7 +306,7 @@ void ArticleDownloader::Run()
FreeConnection(Status == adFinished);
if (m_ArticleWriter.GetDuplicate())
if (m_bDuplicate)
{
Status = adFinished;
}
@@ -331,8 +337,6 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
{
const char* szResponse = NULL;
EStatus Status = adRunning;
m_bWritingStarted = false;
m_pArticleInfo->SetCrc(0);
if (m_pConnection->GetNewsServer()->GetJoinGroup())
{
@@ -373,13 +377,18 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
return Status;
}
// positive answer!
if (g_pOptions->GetDecode())
{
m_YDecoder.Clear();
m_YDecoder.SetAutoSeek(g_pOptions->GetDirectWrite());
m_YDecoder.SetCrcCheck(g_pOptions->GetCrcCheck());
m_UDecoder.Clear();
}
m_pOutFile = NULL;
bool bBody = false;
bool bEnd = false;
const int LineBufSize = 1024*10;
@@ -392,7 +401,7 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
SetLastUpdateTimeNow();
if (tOldTime != m_tLastUpdateTime)
{
AddServerData();
g_pStatMeter->AddServerData(m_pConnection->FetchTotalBytesRead(), m_pConnection->GetNewsServer()->GetID());
}
// Throttle the bandwidth
@@ -409,7 +418,7 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
g_pStatMeter->AddSpeedReading(iLen);
if (g_pOptions->GetAccurateRate())
{
AddServerData();
g_pStatMeter->AddServerData(m_pConnection->FetchTotalBytesRead(), m_pConnection->GetNewsServer()->GetID());
}
// Have we encountered a timeout?
@@ -417,7 +426,8 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
{
if (!IsStopped())
{
detail("Article %s @ %s failed: Unexpected end of article", m_szInfoName, m_szConnectionName);
detail("Article %s @ %s (%s) failed: Unexpected end of article", m_szInfoName,
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost());
}
Status = adFailed;
break;
@@ -451,8 +461,8 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
if (strncmp(p, m_pArticleInfo->GetMessageID(), strlen(m_pArticleInfo->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_szInfoName,
m_szConnectionName, m_pArticleInfo->GetMessageID(), p);
detail("Article %s @ %s (%s) failed: Wrong message-id, expected %s, returned %s", m_szInfoName,
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost(), m_pArticleInfo->GetMessageID(), p);
Status = adFailed;
break;
}
@@ -473,9 +483,21 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
free(szLineBuf);
if (m_pOutFile)
{
if (fclose(m_pOutFile) != 0)
{
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_eFormat == Decoder::efYenc;
char szErrBuf[256];
error("Could not close file %s: %s", (bDirectWrite ? m_szOutputFilename : m_szTempFilename),
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
}
if (!bEnd && Status == adRunning && !IsStopped())
{
detail("Article %s @ %s failed: article incomplete", m_szInfoName, m_szConnectionName);
detail("Article %s @ %s (%s) failed: article incomplete", m_szInfoName,
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost());
Status = adFailed;
}
@@ -487,20 +509,13 @@ ArticleDownloader::EStatus ArticleDownloader::Download()
if (Status == adRunning)
{
FreeConnection(true);
Status = DecodeCheck();
return DecodeCheck();
}
if (m_bWritingStarted)
else
{
m_ArticleWriter.Finish(Status == adFinished);
remove(m_szTempFilename);
return Status;
}
if (Status == adFinished)
{
detail("Successfully downloaded %s", m_szInfoName);
}
return Status;
}
ArticleDownloader::EStatus ArticleDownloader::CheckResponse(const char* szResponse, const char* szComment)
@@ -509,19 +524,21 @@ ArticleDownloader::EStatus ArticleDownloader::CheckResponse(const char* szRespon
{
if (!IsStopped())
{
detail("Article %s @ %s failed, %s: Connection closed by remote host",
m_szInfoName, m_szConnectionName, szComment);
detail("Article %s @ %s (%s) failed, %s: Connection closed by remote host", m_szInfoName,
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost(), szComment);
}
return adConnectError;
}
else if (m_pConnection->GetAuthError() || !strncmp(szResponse, "400", 3) || !strncmp(szResponse, "499", 3))
{
detail("Article %s @ %s failed, %s: %s", m_szInfoName, m_szConnectionName, szComment, szResponse);
detail("Article %s @ %s (%s) failed, %s: %s", m_szInfoName,
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost(), szComment, szResponse);
return adConnectError;
}
else if (!strncmp(szResponse, "41", 2) || !strncmp(szResponse, "42", 2) || !strncmp(szResponse, "43", 2))
{
detail("Article %s @ %s failed, %s: %s", m_szInfoName, m_szConnectionName, szComment, szResponse);
detail("Article %s @ %s (%s) failed, %s: %s", m_szInfoName,
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost(), szComment, szResponse);
return adNotFound;
}
else if (!strncmp(szResponse, "2", 1))
@@ -532,67 +549,230 @@ ArticleDownloader::EStatus ArticleDownloader::CheckResponse(const char* szRespon
else
{
// unknown error, no special handling
detail("Article %s @ %s failed, %s: %s", m_szInfoName, m_szConnectionName, szComment, szResponse);
detail("Article %s @ %s (%s) failed, %s: %s", m_szInfoName,
m_pConnection->GetNewsServer()->GetName(), m_pConnection->GetHost(), szComment, szResponse);
return adFailed;
}
}
bool ArticleDownloader::Write(char* szLine, int iLen)
{
const char* szArticleFilename = NULL;
long long iArticleFileSize = 0;
long long iArticleOffset = 0;
int iArticleSize = 0;
if (!m_pOutFile && !PrepareFile(szLine))
{
return false;
}
if (g_pOptions->GetDecode())
{
bool bOK = false;
if (m_eFormat == Decoder::efYenc)
{
iLen = m_YDecoder.DecodeBuffer(szLine, iLen);
szArticleFilename = m_YDecoder.GetArticleFilename();
iArticleFileSize = m_YDecoder.GetSize();
bOK = m_YDecoder.Write(szLine, iLen, m_pOutFile);
}
else if (m_eFormat == Decoder::efUx)
{
iLen = m_UDecoder.DecodeBuffer(szLine, iLen);
szArticleFilename = m_UDecoder.GetArticleFilename();
bOK = m_UDecoder.Write(szLine, iLen, m_pOutFile);
}
else
{
detail("Decoding %s failed: unsupported encoding", m_szInfoName);
return false;
}
if (iLen > 0 && m_eFormat == Decoder::efYenc)
if (!bOK)
{
if (m_YDecoder.GetBegin() == 0 || m_YDecoder.GetEnd() == 0)
debug("Failed line: %s", szLine);
detail("Decoding %s failed", m_szInfoName);
}
return bOK;
}
else
{
return fwrite(szLine, 1, iLen, m_pOutFile) > 0;
}
}
bool ArticleDownloader::PrepareFile(char* szLine)
{
bool bOpen = false;
// prepare file for writing
if (m_eFormat == Decoder::efYenc)
{
if (!strncmp(szLine, "=ybegin ", 8))
{
if (g_pOptions->GetDupeCheck() &&
m_pFileInfo->GetNZBInfo()->GetDupeMode() != dmForce &&
!m_pFileInfo->GetNZBInfo()->GetManyDupeFiles())
{
return false;
m_pFileInfo->LockOutputFile();
bool bOutputInitialized = m_pFileInfo->GetOutputInitialized();
if (!bOutputInitialized)
{
char* pb = strstr(szLine, " name=");
if (pb)
{
pb += 6; //=strlen(" name=")
char* pe;
for (pe = pb; *pe != '\0' && *pe != '\n' && *pe != '\r'; pe++) ;
if (!m_szArticleFilename)
{
m_szArticleFilename = (char*)malloc(pe - pb + 1);
strncpy(m_szArticleFilename, pb, pe - pb);
m_szArticleFilename[pe - pb] = '\0';
}
}
}
if (!g_pOptions->GetDirectWrite())
{
m_pFileInfo->SetOutputInitialized(true);
}
m_pFileInfo->UnlockOutputFile();
if (!bOutputInitialized && m_szArticleFilename &&
Util::FileExists(m_pFileInfo->GetNZBInfo()->GetDestDir(), m_szArticleFilename))
{
m_bDuplicate = true;
return false;
}
}
if (g_pOptions->GetDirectWrite())
{
char* pb = strstr(szLine, " size=");
if (pb)
{
m_pFileInfo->LockOutputFile();
if (!m_pFileInfo->GetOutputInitialized())
{
pb += 6; //=strlen(" size=")
long iArticleFilesize = atol(pb);
if (!CreateOutputFile(iArticleFilesize))
{
m_pFileInfo->UnlockOutputFile();
return false;
}
m_pFileInfo->SetOutputInitialized(true);
}
m_pFileInfo->UnlockOutputFile();
bOpen = true;
}
}
else
{
bOpen = true;
}
iArticleOffset = m_YDecoder.GetBegin() - 1;
iArticleSize = (int)(m_YDecoder.GetEnd() - m_YDecoder.GetBegin() + 1);
}
}
if (!m_bWritingStarted && iLen > 0)
else
{
if (!m_ArticleWriter.Start(m_eFormat, szArticleFilename, iArticleFileSize, iArticleOffset, iArticleSize))
bOpen = true;
}
if (bOpen)
{
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_eFormat == Decoder::efYenc;
const char* szFilename = bDirectWrite ? m_szOutputFilename : m_szTempFilename;
m_pOutFile = fopen(szFilename, bDirectWrite ? FOPEN_RBP : FOPEN_WB);
if (!m_pOutFile)
{
char szSysErrStr[256];
error("Could not %s file %s! Errcode: %i, %s", bDirectWrite ? "open" : "create", szFilename,
errno, Util::GetLastErrorMessage(szSysErrStr, sizeof(szSysErrStr)));
return false;
}
m_bWritingStarted = true;
if (g_pOptions->GetWriteBufferSize() == -1)
{
setvbuf(m_pOutFile, (char *)NULL, _IOFBF, m_pArticleInfo->GetSize());
}
else if (g_pOptions->GetWriteBufferSize() > 0)
{
setvbuf(m_pOutFile, (char *)NULL, _IOFBF, g_pOptions->GetWriteBufferSize());
}
}
bool bOK = iLen == 0 || m_ArticleWriter.Write(szLine, iLen);
return true;
}
return bOK;
/* creates output file and subdirectores */
bool ArticleDownloader::CreateOutputFile(int iSize)
{
if (g_pOptions->GetDirectWrite() && Util::FileExists(m_szOutputFilename) &&
Util::FileSize(m_szOutputFilename) == iSize)
{
// keep existing old file from previous program session
return true;
}
// delete eventually existing old file from previous program session
remove(m_szOutputFilename);
// ensure the directory exist
char szDestDir[1024];
int iMaxlen = Util::BaseFileName(m_szOutputFilename) - m_szOutputFilename;
if (iMaxlen > 1024-1) iMaxlen = 1024-1;
strncpy(szDestDir, m_szOutputFilename, iMaxlen);
szDestDir[iMaxlen] = '\0';
char szErrBuf[1024];
if (!Util::ForceDirectories(szDestDir, szErrBuf, sizeof(szErrBuf)))
{
error("Could not create directory %s: %s", szDestDir, szErrBuf);
return false;
}
if (!Util::CreateSparseFile(m_szOutputFilename, iSize))
{
error("Could not create file %s", m_szOutputFilename);
return false;
}
return true;
}
void ArticleDownloader::BuildOutputFilename()
{
char szFilename[1024];
snprintf(szFilename, 1024, "%s%i.%03i", g_pOptions->GetTempDir(), m_pFileInfo->GetID(), m_pArticleInfo->GetPartNumber());
szFilename[1024-1] = '\0';
m_pArticleInfo->SetResultFilename(szFilename);
char tmpname[1024];
snprintf(tmpname, 1024, "%s.tmp", szFilename);
tmpname[1024-1] = '\0';
SetTempFilename(tmpname);
if (g_pOptions->GetDirectWrite())
{
m_pFileInfo->LockOutputFile();
if (m_pFileInfo->GetOutputFilename())
{
strncpy(szFilename, m_pFileInfo->GetOutputFilename(), 1024);
szFilename[1024-1] = '\0';
}
else
{
snprintf(szFilename, 1024, "%s%c%i.out.tmp", m_pFileInfo->GetNZBInfo()->GetDestDir(), (int)PATH_SEPARATOR, m_pFileInfo->GetID());
szFilename[1024-1] = '\0';
m_pFileInfo->SetOutputFilename(szFilename);
}
m_pFileInfo->UnlockOutputFile();
SetOutputFilename(szFilename);
}
}
ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
{
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_eFormat == Decoder::efYenc;
if (g_pOptions->GetDecode())
{
SetStatus(adDecoding);
Decoder* pDecoder = NULL;
if (m_eFormat == Decoder::efYenc)
{
pDecoder = &m_YDecoder;
@@ -608,51 +788,71 @@ ArticleDownloader::EStatus ArticleDownloader::DecodeCheck()
}
Decoder::EStatus eStatus = pDecoder->Check();
bool bOK = eStatus == Decoder::eFinished;
if (eStatus == Decoder::eFinished)
if (!bDirectWrite && bOK)
{
if (pDecoder->GetArticleFilename())
if (!Util::MoveFile(m_szTempFilename, m_szResultFilename))
{
free(m_szArticleFilename);
m_szArticleFilename = strdup(pDecoder->GetArticleFilename());
char szErrBuf[256];
error("Could not rename file %s to %s: %s", m_szTempFilename, m_szResultFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
}
if (m_eFormat == Decoder::efYenc)
{
m_pArticleInfo->SetCrc(g_pOptions->GetCrcCheck() ?
m_YDecoder.GetCalculatedCrc() : m_YDecoder.GetExpectedCrc());
}
if (!m_szArticleFilename && pDecoder->GetArticleFilename())
{
m_szArticleFilename = strdup(pDecoder->GetArticleFilename());
}
remove(m_szTempFilename);
if (bOK)
{
detail("Successfully downloaded %s", m_szInfoName);
return adFinished;
}
else if (eStatus == Decoder::eCrcError)
{
detail("Decoding %s failed: CRC-Error", m_szInfoName);
return adCrcError;
}
else if (eStatus == Decoder::eArticleIncomplete)
{
detail("Decoding %s failed: article incomplete", m_szInfoName);
return adFailed;
}
else if (eStatus == Decoder::eInvalidSize)
{
detail("Decoding %s failed: size mismatch", m_szInfoName);
return adFailed;
}
else if (eStatus == Decoder::eNoBinaryData)
{
detail("Decoding %s failed: no binary data found", m_szInfoName);
return adFailed;
}
else
{
detail("Decoding %s failed", m_szInfoName);
return adFailed;
remove(m_szResultFilename);
if (eStatus == Decoder::eCrcError)
{
detail("Decoding %s failed: CRC-Error", m_szInfoName);
return adCrcError;
}
else if (eStatus == Decoder::eArticleIncomplete)
{
detail("Decoding %s failed: article incomplete", m_szInfoName);
return adFailed;
}
else if (eStatus == Decoder::eInvalidSize)
{
detail("Decoding %s failed: size mismatch", m_szInfoName);
return adFailed;
}
else if (eStatus == Decoder::eNoBinaryData)
{
detail("Decoding %s failed: no binary data found", m_szInfoName);
return adFailed;
}
else
{
detail("Decoding %s failed", m_szInfoName);
return adFailed;
}
}
}
else
{
// rawmode
if (Util::MoveFile(m_szTempFilename, m_szResultFilename))
{
detail("Article %s successfully downloaded", m_szInfoName);
}
else
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", m_szTempFilename, m_szResultFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
return adFinished;
}
}
@@ -665,7 +865,8 @@ void ArticleDownloader::LogDebugInfo()
#else
ctime_r(&m_tLastUpdateTime, szTime);
#endif
info(" Download: Status=%i, LastUpdateTime=%s, InfoName=%s", m_eStatus, szTime, m_szInfoName);
info(" Download: status=%i, LastUpdateTime=%s, filename=%s", m_eStatus, szTime, Util::BaseFileName(GetTempFilename()));
}
void ArticleDownloader::Stop()
@@ -708,16 +909,345 @@ void ArticleDownloader::FreeConnection(bool bKeepConnected)
{
m_pConnection->Disconnect();
}
AddServerData();
g_pStatMeter->AddServerData(m_pConnection->FetchTotalBytesRead(), m_pConnection->GetNewsServer()->GetID());
g_pServerPool->FreeConnection(m_pConnection, true);
m_pConnection = NULL;
m_mutexConnection.Unlock();
}
}
void ArticleDownloader::AddServerData()
void ArticleDownloader::CompleteFileParts()
{
int iBytesRead = m_pConnection->FetchTotalBytesRead();
g_pStatMeter->AddServerData(iBytesRead, m_pConnection->GetNewsServer()->GetID());
m_iDownloadedSize += iBytesRead;
debug("Completing file parts");
debug("ArticleFilename: %s", m_pFileInfo->GetFilename());
SetStatus(adJoining);
bool bDirectWrite = g_pOptions->GetDirectWrite() && m_pFileInfo->GetOutputInitialized();
char szNZBName[1024];
char szNZBDestDir[1024];
// the locking is needed for accessing the memebers of NZBInfo
DownloadQueue::Lock();
strncpy(szNZBName, m_pFileInfo->GetNZBInfo()->GetName(), 1024);
strncpy(szNZBDestDir, m_pFileInfo->GetNZBInfo()->GetDestDir(), 1024);
DownloadQueue::Unlock();
szNZBName[1024-1] = '\0';
szNZBDestDir[1024-1] = '\0';
char InfoFilename[1024];
snprintf(InfoFilename, 1024, "%s%c%s", szNZBName, (int)PATH_SEPARATOR, m_pFileInfo->GetFilename());
InfoFilename[1024-1] = '\0';
if (!g_pOptions->GetDecode())
{
detail("Moving articles for %s", InfoFilename);
}
else if (bDirectWrite)
{
detail("Checking articles for %s", InfoFilename);
}
else
{
detail("Joining articles for %s", InfoFilename);
}
// Ensure the DstDir is created
char szErrBuf[1024];
if (!Util::ForceDirectories(szNZBDestDir, szErrBuf, sizeof(szErrBuf)))
{
error("Could not create directory %s: %s", szNZBDestDir, szErrBuf);
SetStatus(adJoined);
return;
}
char ofn[1024];
Util::MakeUniqueFilename(ofn, 1024, szNZBDestDir, m_pFileInfo->GetFilename());
FILE* outfile = NULL;
char tmpdestfile[1024];
snprintf(tmpdestfile, 1024, "%s.tmp", ofn);
tmpdestfile[1024-1] = '\0';
if (g_pOptions->GetDecode() && !bDirectWrite)
{
remove(tmpdestfile);
outfile = fopen(tmpdestfile, FOPEN_WBP);
if (!outfile)
{
error("Could not create file %s!", tmpdestfile);
SetStatus(adJoined);
return;
}
if (g_pOptions->GetWriteBufferSize() == -1 && (*m_pFileInfo->GetArticles())[0])
{
setvbuf(outfile, (char *)NULL, _IOFBF, (*m_pFileInfo->GetArticles())[0]->GetSize());
}
else if (g_pOptions->GetWriteBufferSize() > 0)
{
setvbuf(outfile, (char *)NULL, _IOFBF, g_pOptions->GetWriteBufferSize());
}
}
else if (!g_pOptions->GetDecode())
{
remove(tmpdestfile);
if (!Util::CreateDirectory(ofn))
{
error("Could not create directory %s! Errcode: %i", ofn, errno);
SetStatus(adJoined);
return;
}
}
bool complete = true;
int iBrokenCount = 0;
static const int BUFFER_SIZE = 1024 * 50;
char* buffer = NULL;
if (g_pOptions->GetDecode() && !bDirectWrite)
{
buffer = (char*)malloc(BUFFER_SIZE);
}
for (FileInfo::Articles::iterator it = m_pFileInfo->GetArticles()->begin(); it != m_pFileInfo->GetArticles()->end(); it++)
{
ArticleInfo* pa = *it;
if (pa->GetStatus() != ArticleInfo::aiFinished)
{
iBrokenCount++;
complete = false;
}
else if (g_pOptions->GetDecode() && !bDirectWrite)
{
FILE* infile;
const char* fn = pa->GetResultFilename();
infile = fopen(fn, FOPEN_RB);
if (infile)
{
int cnt = BUFFER_SIZE;
while (cnt == BUFFER_SIZE)
{
cnt = (int)fread(buffer, 1, BUFFER_SIZE, infile);
fwrite(buffer, 1, cnt, outfile);
SetLastUpdateTimeNow();
}
fclose(infile);
}
else
{
complete = false;
iBrokenCount++;
detail("Could not find file %s. Status is broken", fn);
}
}
else if (!g_pOptions->GetDecode())
{
const char* fn = pa->GetResultFilename();
char dstFileName[1024];
snprintf(dstFileName, 1024, "%s%c%03i", ofn, (int)PATH_SEPARATOR, pa->GetPartNumber());
dstFileName[1024-1] = '\0';
if (!Util::MoveFile(fn, dstFileName))
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", fn, dstFileName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
}
}
free(buffer);
if (outfile)
{
fclose(outfile);
if (!Util::MoveFile(tmpdestfile, ofn))
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", tmpdestfile, ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
}
if (bDirectWrite)
{
if (!Util::MoveFile(m_szOutputFilename, ofn))
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", m_szOutputFilename, ofn, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
// if destination directory was changed delete the old directory (if empty)
int iLen = strlen(szNZBDestDir);
if (!(!strncmp(szNZBDestDir, m_szOutputFilename, iLen) &&
(m_szOutputFilename[iLen] == PATH_SEPARATOR || m_szOutputFilename[iLen] == ALT_PATH_SEPARATOR)))
{
debug("Checking old dir for: %s", m_szOutputFilename);
char szOldDestDir[1024];
int iMaxlen = Util::BaseFileName(m_szOutputFilename) - m_szOutputFilename;
if (iMaxlen > 1024-1) iMaxlen = 1024-1;
strncpy(szOldDestDir, m_szOutputFilename, iMaxlen);
szOldDestDir[iMaxlen] = '\0';
if (Util::DirEmpty(szOldDestDir))
{
debug("Deleting old dir: %s", szOldDestDir);
rmdir(szOldDestDir);
}
}
}
if (!bDirectWrite)
{
for (FileInfo::Articles::iterator it = m_pFileInfo->GetArticles()->begin(); it != m_pFileInfo->GetArticles()->end(); it++)
{
ArticleInfo* pa = *it;
remove(pa->GetResultFilename());
}
}
if (complete)
{
info("Successfully downloaded %s", InfoFilename);
}
else
{
warn("%i of %i article downloads failed for \"%s\"",
iBrokenCount + m_pFileInfo->GetMissedArticles(),
m_pFileInfo->GetTotalArticles(), InfoFilename);
if (g_pOptions->GetCreateBrokenLog())
{
char szBrokenLogName[1024];
snprintf(szBrokenLogName, 1024, "%s%c_brokenlog.txt", szNZBDestDir, (int)PATH_SEPARATOR);
szBrokenLogName[1024-1] = '\0';
FILE* file = fopen(szBrokenLogName, FOPEN_AB);
fprintf(file, "%s (%i/%i)%s", m_pFileInfo->GetFilename(),
m_pFileInfo->GetTotalArticles() - iBrokenCount - m_pFileInfo->GetMissedArticles(),
m_pFileInfo->GetTotalArticles(), LINE_ENDING);
fclose(file);
}
}
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
m_pFileInfo->GetNZBInfo()->GetCompletedFiles()->push_back(strdup(ofn));
if (strcmp(m_pFileInfo->GetNZBInfo()->GetDestDir(), szNZBDestDir))
{
// destination directory was changed during completion, need to move the file
MoveCompletedFiles(m_pFileInfo->GetNZBInfo(), szNZBDestDir);
}
DownloadQueue::Unlock();
SetStatus(adJoined);
}
bool ArticleDownloader::MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldDestDir)
{
if (pNZBInfo->GetCompletedFiles()->empty())
{
return true;
}
// Ensure the DstDir is created
char szErrBuf[1024];
if (!Util::ForceDirectories(pNZBInfo->GetDestDir(), szErrBuf, sizeof(szErrBuf)))
{
error("Could not create directory %s: %s", pNZBInfo->GetDestDir(), szErrBuf);
return false;
}
// move already downloaded files to new destination
for (NZBInfo::Files::iterator it = pNZBInfo->GetCompletedFiles()->begin(); it != pNZBInfo->GetCompletedFiles()->end(); it++)
{
char* szFileName = *it;
char szNewFileName[1024];
snprintf(szNewFileName, 1024, "%s%c%s", pNZBInfo->GetDestDir(), (int)PATH_SEPARATOR, Util::BaseFileName(szFileName));
szNewFileName[1024-1] = '\0';
// check if file was not moved already
if (strcmp(szFileName, szNewFileName))
{
// prevent overwriting of existing files
Util::MakeUniqueFilename(szNewFileName, 1024, pNZBInfo->GetDestDir(), Util::BaseFileName(szFileName));
detail("Moving file %s to %s", szFileName, szNewFileName);
if (Util::MoveFile(szFileName, szNewFileName))
{
free(szFileName);
*it = strdup(szNewFileName);
}
else
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", szFileName, szNewFileName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
}
}
// move brokenlog.txt
if (g_pOptions->GetCreateBrokenLog())
{
char szOldBrokenLogName[1024];
snprintf(szOldBrokenLogName, 1024, "%s%c_brokenlog.txt", szOldDestDir, (int)PATH_SEPARATOR);
szOldBrokenLogName[1024-1] = '\0';
if (Util::FileExists(szOldBrokenLogName))
{
char szBrokenLogName[1024];
snprintf(szBrokenLogName, 1024, "%s%c_brokenlog.txt", pNZBInfo->GetDestDir(), (int)PATH_SEPARATOR);
szBrokenLogName[1024-1] = '\0';
detail("Moving file %s to %s", szOldBrokenLogName, szBrokenLogName);
if (Util::FileExists(szBrokenLogName))
{
// copy content to existing new file, then delete old file
FILE* outfile;
outfile = fopen(szBrokenLogName, FOPEN_AB);
if (outfile)
{
FILE* infile;
infile = fopen(szOldBrokenLogName, FOPEN_RB);
if (infile)
{
static const int BUFFER_SIZE = 1024 * 50;
int cnt = BUFFER_SIZE;
char* buffer = (char*)malloc(BUFFER_SIZE);
while (cnt == BUFFER_SIZE)
{
cnt = (int)fread(buffer, 1, BUFFER_SIZE, infile);
fwrite(buffer, 1, cnt, outfile);
}
fclose(infile);
free(buffer);
remove(szOldBrokenLogName);
}
else
{
error("Could not open file %s", szOldBrokenLogName);
}
fclose(outfile);
}
else
{
error("Could not open file %s", szBrokenLogName);
}
}
else
{
// move to new destination
if (!Util::MoveFile(szOldBrokenLogName, szBrokenLogName))
{
char szErrBuf[256];
error("Could not move file %s to %s: %s", szOldBrokenLogName, szBrokenLogName, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
}
}
}
// delete old directory (if empty)
if (Util::DirEmpty(szOldDestDir))
{
rmdir(szOldDestDir);
}
return true;
}

View File

@@ -34,7 +34,6 @@
#include "Thread.h"
#include "NNTPConnection.h"
#include "Decoder.h"
#include "ArticleWriter.h"
class ArticleDownloader : public Thread, public Subject
{
@@ -48,20 +47,13 @@ public:
adFailed,
adRetry,
adCrcError,
adDecoding,
adJoining,
adJoined,
adNotFound,
adConnectError,
adFatalError
};
class ArticleWriterImpl : public ArticleWriter
{
private:
ArticleDownloader* m_pOwner;
protected:
virtual void SetLastUpdateTimeNow() { m_pOwner->SetLastUpdateTimeNow(); }
public:
void SetOwner(ArticleDownloader* pOwner) { m_pOwner = pOwner; }
};
private:
FileInfo* m_pFileInfo;
@@ -69,25 +61,31 @@ private:
NNTPConnection* m_pConnection;
EStatus m_eStatus;
Mutex m_mutexConnection;
char* m_szInfoName;
char m_szConnectionName[250];
const char* m_szResultFilename;
char* m_szTempFilename;
char* m_szArticleFilename;
char* m_szInfoName;
char* m_szOutputFilename;
time_t m_tLastUpdateTime;
Decoder::EFormat m_eFormat;
YDecoder m_YDecoder;
UDecoder m_UDecoder;
ArticleWriterImpl m_ArticleWriter;
FILE* m_pOutFile;
bool m_bDuplicate;
ServerStatList m_ServerStats;
bool m_bWritingStarted;
int m_iDownloadedSize;
EStatus Download();
bool Write(char* szLine, int iLen);
bool PrepareFile(char* szLine);
bool CreateOutputFile(int iSize);
void BuildOutputFilename();
EStatus DecodeCheck();
void FreeConnection(bool bKeepConnected);
EStatus CheckResponse(const char* szResponse, const char* szComment);
void SetStatus(EStatus eStatus) { m_eStatus = eStatus; }
bool Write(char* szLine, int iLen);
void AddServerData();
const char* GetTempFilename() { return m_szTempFilename; }
void SetTempFilename(const char* v);
void SetOutputFilename(const char* v);
public:
ArticleDownloader();
@@ -104,12 +102,11 @@ public:
time_t GetLastUpdateTime() { return m_tLastUpdateTime; }
void SetLastUpdateTimeNow() { m_tLastUpdateTime = ::time(NULL); }
const char* GetArticleFilename() { return m_szArticleFilename; }
void SetInfoName(const char* szInfoName);
void SetInfoName(const char* v);
const char* GetInfoName() { return m_szInfoName; }
const char* GetConnectionName() { return m_szConnectionName; }
void CompleteFileParts();
static bool MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldDestDir);
void SetConnection(NNTPConnection* pConnection) { m_pConnection = pConnection; }
void CompleteFileParts() { m_ArticleWriter.CompleteFileParts(); }
int GetDownloadedSize() { return m_iDownloadedSize; }
void LogDebugInfo();
};

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,102 +0,0 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2014 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Revision$
* $Date$
*
*/
#ifndef ARTICLEWRITER_H
#define ARTICLEWRITER_H
#include "DownloadInfo.h"
#include "Decoder.h"
class ArticleWriter
{
private:
FileInfo* m_pFileInfo;
ArticleInfo* m_pArticleInfo;
FILE* m_pOutFile;
char* m_szTempFilename;
char* m_szOutputFilename;
const char* m_szResultFilename;
Decoder::EFormat m_eFormat;
char* m_pArticleData;
long long m_iArticleOffset;
int m_iArticleSize;
int m_iArticlePtr;
bool m_bFlushing;
bool m_bDuplicate;
char* m_szInfoName;
bool PrepareFile(char* szLine);
bool CreateOutputFile(long long iSize);
void BuildOutputFilename();
bool IsFileCached();
void SetWriteBuffer(FILE* pOutFile, int iRecSize);
protected:
virtual void SetLastUpdateTimeNow() {}
public:
ArticleWriter();
~ArticleWriter();
void SetInfoName(const char* szInfoName);
void SetFileInfo(FileInfo* pFileInfo) { m_pFileInfo = pFileInfo; }
void SetArticleInfo(ArticleInfo* pArticleInfo) { m_pArticleInfo = pArticleInfo; }
void Prepare();
bool Start(Decoder::EFormat eFormat, const char* szFilename, long long iFileSize, long long iArticleOffset, int iArticleSize);
bool Write(char* szBufffer, int iLen);
void Finish(bool bSuccess);
bool GetDuplicate() { return m_bDuplicate; }
void CompleteFileParts();
static bool MoveCompletedFiles(NZBInfo* pNZBInfo, const char* szOldDestDir);
void FlushCache();
};
class ArticleCache : public Thread
{
private:
size_t m_iAllocated;
bool m_bFlushing;
Mutex m_mutexAlloc;
Mutex m_mutexFlush;
Mutex m_mutexContent;
FileInfo* m_pFileInfo;
bool CheckFlush(bool bFlushEverything);
public:
ArticleCache();
virtual void Run();
void* Alloc(int iSize);
void* Realloc(void* buf, int iOldSize, int iNewSize);
void Free(int iSize);
void LockFlush();
void UnlockFlush();
void LockContent() { m_mutexContent.Lock(); }
void UnlockContent() { m_mutexContent.Unlock(); }
bool GetFlushing() { return m_bFlushing; }
size_t GetAllocated() { return m_iAllocated; }
bool FileBusy(FileInfo* pFileInfo) { return pFileInfo == m_pFileInfo; }
};
#endif

View File

@@ -1,7 +1,8 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 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,11 +45,14 @@
#include "Util.h"
const char* Decoder::FormatNames[] = { "Unknown", "yEnc", "UU" };
unsigned int YDecoder::crc_tab[256];
Decoder::Decoder()
{
debug("Creating Decoder");
m_szSrcFilename = NULL;
m_szDestFilename = NULL;
m_szArticleFilename = NULL;
}
@@ -103,6 +107,17 @@ Decoder::EFormat Decoder::DetectFormat(const char* buffer, int len)
* YDecoder: fast implementation of yEnc-Decoder
*/
void YDecoder::Init()
{
debug("Initializing global decoder");
crc32gentab();
}
void YDecoder::Final()
{
debug("Finalizing global Decoder");
}
YDecoder::YDecoder()
{
Clear();
@@ -120,13 +135,69 @@ void YDecoder::Clear()
m_lExpectedCRC = 0;
m_lCalculatedCRC = 0xFFFFFFFF;
m_iBegin = 0;
m_iEnd = 0;
m_iEnd = 0xFFFFFFFF;
m_iSize = 0;
m_iEndSize = 0;
m_bAutoSeek = false;
m_bNeedSetPos = false;
m_bCrcCheck = false;
}
int YDecoder::DecodeBuffer(char* buffer, int len)
/* from crc32.c (http://www.koders.com/c/fid699AFE0A656F0022C9D6B9D1743E697B69CE5815.aspx)
*
* (c) 1999,2000 Krzysztof Dabrowski
* (c) 1999,2000 ElysiuM deeZine
* Released under GPL (thanks)
*
* chksum_crc32gentab() -- to a global crc_tab[256], this one will
* calculate the crcTable for crc32-checksums.
* it is generated to the polynom [..]
*/
void YDecoder::crc32gentab()
{
unsigned long crc, poly;
int i, j;
poly = 0xEDB88320L;
for (i = 0; i < 256; i++)
{
crc = i;
for (j = 8; j > 0; j--)
{
if (crc & 1)
{
crc = (crc >> 1) ^ poly;
}
else
{
crc >>= 1;
}
}
crc_tab[i] = crc;
}
}
/* This is 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.
*/
unsigned long YDecoder::crc32m(unsigned long startCrc, unsigned char *block, unsigned int length)
{
register unsigned long crc = startCrc;
for (unsigned long i = 0; i < length; i++)
{
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
}
return crc;
}
unsigned int YDecoder::DecodeBuffer(char* buffer)
{
if (m_bBody && !m_bEnd)
{
@@ -144,7 +215,7 @@ int YDecoder::DecodeBuffer(char* buffer, int len)
if (pb)
{
pb += 6; //=strlen(" size=")
m_iEndSize = (long long)atoll(pb);
m_iEndSize = (int)atoi(pb);
}
return 0;
}
@@ -176,9 +247,9 @@ BreakLoop:
if (m_bCrcCheck)
{
m_lCalculatedCRC = Util::Crc32m(m_lCalculatedCRC, (unsigned char *)buffer, (unsigned int)(optr - buffer));
m_lCalculatedCRC = crc32m(m_lCalculatedCRC, (unsigned char *)buffer, (unsigned int)(optr - buffer));
}
return optr - buffer;
return (unsigned int)(optr - buffer);
}
else
{
@@ -200,7 +271,7 @@ BreakLoop:
if (pb)
{
pb += 6; //=strlen(" size=")
m_iSize = (long long)atoll(pb);
m_iSize = (int)atoi(pb);
}
m_bPart = strstr(buffer, " part=");
if (!m_bPart)
@@ -218,13 +289,13 @@ BreakLoop:
if (pb)
{
pb += 7; //=strlen(" begin=")
m_iBegin = (long long)atoll(pb);
m_iBegin = (int)atoi(pb);
}
pb = strstr(buffer, " end=");
if (pb)
{
pb += 5; //=strlen(" end=")
m_iEnd = (long long)atoll(pb);
m_iEnd = (int)atoi(pb);
}
}
}
@@ -232,6 +303,28 @@ BreakLoop:
return 0;
}
bool YDecoder::Write(char* buffer, int len, FILE* outfile)
{
unsigned int wcnt = DecodeBuffer(buffer);
if (wcnt > 0)
{
if (m_bNeedSetPos)
{
if (m_iBegin == 0 || m_iEnd == 0xFFFFFFFF || !outfile)
{
return false;
}
if (fseek(outfile, m_iBegin - 1, SEEK_SET))
{
return false;
}
m_bNeedSetPos = false;
}
fwrite(buffer, 1, wcnt, outfile);
}
return true;
}
Decoder::EStatus YDecoder::Check()
{
m_lCalculatedCRC ^= 0xFFFFFFFF;
@@ -286,7 +379,7 @@ void UDecoder::Clear()
#define UU_DECODE_CHAR(c) (c == '`' ? 0 : (((c) - ' ') & 077))
int UDecoder::DecodeBuffer(char* buffer, int len)
unsigned int UDecoder::DecodeBuffer(char* buffer, int len)
{
if (!m_bBody)
{
@@ -353,12 +446,22 @@ int UDecoder::DecodeBuffer(char* buffer, int len)
}
}
return optr - buffer;
return (unsigned int)(optr - buffer);
}
return 0;
}
bool UDecoder::Write(char* buffer, int len, FILE* outfile)
{
unsigned int wcnt = DecodeBuffer(buffer, len);
if (wcnt > 0)
{
fwrite(buffer, 1, wcnt, outfile);
}
return true;
}
Decoder::EStatus UDecoder::Check()
{
if (!m_bBody)

View File

@@ -1,7 +1,8 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2008 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
@@ -49,6 +50,8 @@ public:
static const char* FormatNames[];
protected:
const char* m_szSrcFilename;
const char* m_szDestFilename;
char* m_szArticleFilename;
public:
@@ -56,7 +59,9 @@ public:
virtual ~Decoder();
virtual EStatus Check() = 0;
virtual void Clear();
virtual int DecodeBuffer(char* buffer, int len) = 0;
virtual bool Write(char* buffer, int len, FILE* outfile) = 0;
void SetSrcFilename(const char* szSrcFilename) { m_szSrcFilename = szSrcFilename; }
void SetDestFilename(const char* szDestFilename) { m_szDestFilename = szDestFilename; }
const char* GetArticleFilename() { return m_szArticleFilename; }
static EFormat DetectFormat(const char* buffer, int len);
};
@@ -64,6 +69,7 @@ public:
class YDecoder: public Decoder
{
protected:
static unsigned int crc_tab[256];
bool m_bBegin;
bool m_bPart;
bool m_bBody;
@@ -71,23 +77,28 @@ protected:
bool m_bCrc;
unsigned long m_lExpectedCRC;
unsigned long m_lCalculatedCRC;
long long m_iBegin;
long long m_iEnd;
long long m_iSize;
long long m_iEndSize;
unsigned long m_iBegin;
unsigned long m_iEnd;
unsigned long m_iSize;
unsigned long m_iEndSize;
bool m_bAutoSeek;
bool m_bNeedSetPos;
bool m_bCrcCheck;
unsigned int DecodeBuffer(char* buffer);
static void crc32gentab();
unsigned long crc32m(unsigned long startCrc, unsigned char *block, unsigned int length);
public:
YDecoder();
virtual EStatus Check();
virtual void Clear();
virtual int DecodeBuffer(char* buffer, int len);
virtual bool Write(char* buffer, int len, FILE* outfile);
void SetAutoSeek(bool bAutoSeek) { m_bAutoSeek = m_bNeedSetPos = bAutoSeek; }
void SetCrcCheck(bool bCrcCheck) { m_bCrcCheck = bCrcCheck; }
long long GetBegin() { return m_iBegin; }
long long GetEnd() { return m_iEnd; }
long long GetSize() { return m_iSize; }
unsigned long GetExpectedCrc() { return m_lExpectedCRC; }
unsigned long GetCalculatedCrc() { return m_lCalculatedCRC; }
static void Init();
static void Final();
};
class UDecoder: public Decoder
@@ -96,11 +107,13 @@ private:
bool m_bBody;
bool m_bEnd;
unsigned int DecodeBuffer(char* buffer, int len);
public:
UDecoder();
virtual EStatus Check();
virtual void Clear();
virtual int DecodeBuffer(char* buffer, int len);
virtual bool Write(char* buffer, int len, FILE* outfile);
};
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 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,7 +29,6 @@
#ifdef WIN32
#include "win32.h"
#include "Mmsystem.h"
#endif
#ifndef DISABLE_PARCHECK
@@ -38,17 +37,17 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#ifndef WIN32
#ifdef WIN32
#include <par2cmdline.h>
#include <par2repairer.h>
#else
#include <unistd.h>
#include <libpar2/par2cmdline.h>
#include <libpar2/par2repairer.h>
#endif
#include <vector>
#include <algorithm>
#include "par2cmdline.h"
#include "par2repairer.h"
#include "nzbget.h"
#include "Thread.h"
#include "ParChecker.h"
#include "ParCoordinator.h"
#include "Log.h"
@@ -67,77 +66,25 @@ const char* Par2CmdLineErrStr[] = { "OK",
"internal error occurred",
"out of memory" };
// Sleep interval for synchronisation (microseconds)
#ifdef WIN32
// Windows doesn't allow sleep intervals less than one millisecond
#define SYNC_SLEEP_INTERVAL 1000
#else
#define SYNC_SLEEP_INTERVAL 100
#endif
class RepairThread;
class Repairer : public Par2Repairer
{
private:
typedef vector<Thread*> Threads;
CommandLine commandLine;
ParChecker* m_pOwner;
Threads m_Threads;
bool m_bParallel;
#ifdef HAVE_SPINLOCK
SpinLock progresslock;
#else
Mutex progresslock;
#endif
virtual void BeginRepair();
virtual void EndRepair();
void RepairBlock(u32 inputindex, u32 outputindex, size_t blocklength);
protected:
virtual void sig_filename(std::string filename) { m_pOwner->signal_filename(filename); }
virtual void sig_progress(double progress) { m_pOwner->signal_progress(progress); }
virtual void sig_done(std::string filename, int available, int total) { m_pOwner->signal_done(filename, available, total); }
virtual bool ScanDataFile(DiskFile *diskfile, Par2RepairerSourceFile* &sourcefile,
MatchType &matchtype, MD5Hash &hashfull, MD5Hash &hash16k, u32 &count);
virtual bool RepairData(u32 inputindex, size_t blocklength);
CommandLine commandLine;
public:
Repairer(ParChecker* pOwner) { m_pOwner = pOwner; }
Result PreProcess(const char *szParFilename);
Result Process(bool dorepair);
Result PreProcess(const char *szParFilename);
Result Process(bool dorepair);
friend class ParChecker;
friend class RepairThread;
};
class RepairThread : public Thread
{
private:
Repairer* m_pOwner;
u32 m_inputindex;
u32 m_outputindex;
size_t m_blocklength;
volatile bool m_bWorking;
protected:
virtual void Run();
public:
RepairThread(Repairer* pOwner) { this->m_pOwner = pOwner; m_bWorking = false; }
void RepairBlock(u32 inputindex, u32 outputindex, size_t blocklength);
bool IsWorking() { return m_bWorking; }
};
Result Repairer::PreProcess(const char *szParFilename)
{
char szMemParam[20];
snprintf(szMemParam, 20, "-m%i", g_pOptions->GetParBuffer());
szMemParam[20-1] = '\0';
#ifdef HAVE_PAR2_BUGFIXES_V2
// Ensure linking against the patched version of libpar2
BugfixesPatchVersion2();
#endif
if (g_pOptions->GetParScan() == Options::psFull)
{
@@ -151,16 +98,16 @@ Result Repairer::PreProcess(const char *szParFilename)
szBasename[1] = '\0';
}
const char* argv[] = { "par2", "r", "-v", "-v", szMemParam, szParFilename, szWildcardParam };
if (!commandLine.Parse(7, (char**)argv))
const char* argv[] = { "par2", "r", "-v", "-v", szParFilename, szWildcardParam };
if (!commandLine.Parse(6, (char**)argv))
{
return eInvalidCommandLineArguments;
}
}
else
{
const char* argv[] = { "par2", "r", "-v", "-v", szMemParam, szParFilename };
if (!commandLine.Parse(6, (char**)argv))
const char* argv[] = { "par2", "r", "-v", "-v", szParFilename };
if (!commandLine.Parse(5, (char**)argv))
{
return eInvalidCommandLineArguments;
}
@@ -175,177 +122,6 @@ Result Repairer::Process(bool dorepair)
}
bool Repairer::ScanDataFile(DiskFile *diskfile, Par2RepairerSourceFile* &sourcefile,
MatchType &matchtype, MD5Hash &hashfull, MD5Hash &hash16k, u32 &count)
{
if (m_pOwner->GetParQuick() && sourcefile)
{
string path;
string name;
DiskFile::SplitFilename(diskfile->FileName(), path, name);
sig_filename(name);
int iAvailableBlocks = sourcefile->BlockCount();
ParChecker::EFileStatus eFileStatus = m_pOwner->VerifyDataFile(diskfile, sourcefile, &iAvailableBlocks);
if (eFileStatus != ParChecker::fsUnknown)
{
sig_done(name, iAvailableBlocks, sourcefile->BlockCount());
sig_progress(1000.0);
matchtype = eFileStatus == ParChecker::fsSuccess ? eFullMatch : ParChecker::fsPartial ? ePartialMatch : eNoMatch;
return true;
}
}
return Par2Repairer::ScanDataFile(diskfile, sourcefile, matchtype, hashfull, hash16k, count);
}
void Repairer::BeginRepair()
{
int iMaxThreads = g_pOptions->GetParThreads() > 0 ? g_pOptions->GetParThreads() : Util::NumberOfCpuCores();
iMaxThreads = iMaxThreads > 0 ? iMaxThreads : 1;
int iThreads = iMaxThreads > (int)missingblockcount ? (int)missingblockcount : iMaxThreads;
m_pOwner->PrintMessage(Message::mkInfo, "Using %i of max %i thread(s) to repair %i block(s) for %s",
iThreads, iMaxThreads, (int)missingblockcount, m_pOwner->m_szNZBName);
m_bParallel = iThreads > 1;
if (m_bParallel)
{
for (int i = 0; i < iThreads; i++)
{
RepairThread* pRepairThread = new RepairThread(this);
m_Threads.push_back(pRepairThread);
pRepairThread->SetAutoDestroy(true);
pRepairThread->Start();
}
#ifdef WIN32
timeBeginPeriod(1);
#endif
}
}
void Repairer::EndRepair()
{
if (m_bParallel)
{
for (Threads::iterator it = m_Threads.begin(); it != m_Threads.end(); it++)
{
RepairThread* pRepairThread = (RepairThread*)*it;
pRepairThread->Stop();
}
#ifdef WIN32
timeEndPeriod(1);
#endif
}
}
bool Repairer::RepairData(u32 inputindex, size_t blocklength)
{
if (!m_bParallel)
{
return false;
}
for (u32 outputindex = 0; outputindex < missingblockcount; )
{
bool bJobAdded = false;
for (Threads::iterator it = m_Threads.begin(); it != m_Threads.end(); it++)
{
RepairThread* pRepairThread = (RepairThread*)*it;
if (!pRepairThread->IsWorking())
{
pRepairThread->RepairBlock(inputindex, outputindex, blocklength);
outputindex++;
bJobAdded = true;
break;
}
}
if (cancelled)
{
break;
}
if (!bJobAdded)
{
usleep(SYNC_SLEEP_INTERVAL);
}
}
// Wait until all m_Threads complete their jobs
bool bWorking = true;
while (bWorking)
{
bWorking = false;
for (Threads::iterator it = m_Threads.begin(); it != m_Threads.end(); it++)
{
RepairThread* pRepairThread = (RepairThread*)*it;
if (pRepairThread->IsWorking())
{
bWorking = true;
usleep(SYNC_SLEEP_INTERVAL);
break;
}
}
}
return true;
}
void Repairer::RepairBlock(u32 inputindex, u32 outputindex, size_t blocklength)
{
// Select the appropriate part of the output buffer
void *outbuf = &((u8*)outputbuffer)[chunksize * outputindex];
// Process the data
rs.Process(blocklength, inputindex, inputbuffer, outputindex, outbuf);
if (noiselevel > CommandLine::nlQuiet)
{
// Update a progress indicator
progresslock.Lock();
u32 oldfraction = (u32)(1000 * progress / totaldata);
progress += blocklength;
u32 newfraction = (u32)(1000 * progress / totaldata);
progresslock.Unlock();
if (oldfraction != newfraction)
{
sig_progress(newfraction);
}
}
}
void RepairThread::Run()
{
while (!IsStopped())
{
if (m_bWorking)
{
m_pOwner->RepairBlock(m_inputindex, m_outputindex, m_blocklength);
m_bWorking = false;
}
else
{
usleep(SYNC_SLEEP_INTERVAL);
}
}
}
void RepairThread::RepairBlock(u32 inputindex, u32 outputindex, size_t blocklength)
{
m_inputindex = inputindex;
m_outputindex = outputindex;
m_blocklength = blocklength;
m_bWorking = true;
}
class MissingFilesComparator
{
private:
@@ -376,24 +152,6 @@ bool MissingFilesComparator::operator()(CommandLine::ExtraFile* pFile1, CommandL
}
ParChecker::Segment::Segment(bool bSuccess, long long iOffset, int iSize, unsigned long lCrc)
{
m_bSuccess = bSuccess;
m_iOffset = iOffset;
m_iSize = iSize;
m_lCrc = lCrc;
}
ParChecker::SegmentList::~SegmentList()
{
for (iterator it = begin(); it != end(); it++)
{
delete *it;
}
}
ParChecker::ParChecker()
{
debug("Creating ParChecker");
@@ -412,8 +170,6 @@ ParChecker::ParChecker()
m_bVerifyingExtraFiles = false;
m_bCancelled = false;
m_eStage = ptLoadingPars;
m_bParQuick = false;
m_bForceRepair = false;
}
ParChecker::~ParChecker()
@@ -470,29 +226,17 @@ void ParChecker::SetInfoName(const char * szInfoName)
}
void ParChecker::Run()
{
m_eStatus = RunParCheckAll();
if (m_eStatus == psRepairNotNeeded && m_bParQuick && m_bForceRepair && !m_bCancelled)
{
PrintMessage(Message::mkInfo, "Performing full par-check for %s", m_szNZBName);
m_bParQuick = false;
m_eStatus = RunParCheckAll();
}
Completed();
}
ParChecker::EStatus ParChecker::RunParCheckAll()
{
ParCoordinator::ParFileList fileList;
if (!ParCoordinator::FindMainPars(m_szDestDir, &fileList))
{
PrintMessage(Message::mkError, "Could not start par-check for %s. Could not find any par-files", m_szNZBName);
return psFailed;
m_eStatus = psFailed;
Completed();
return;
}
EStatus eAllStatus = psRepairNotNeeded;
m_eStatus = psRepairNotNeeded;
m_bCancelled = false;
for (ParCoordinator::ParFileList::iterator it = fileList.begin(); it != fileList.end(); it++)
@@ -522,9 +266,9 @@ ParChecker::EStatus ParChecker::RunParCheckAll()
EStatus eStatus = RunParCheck(szFullParFilename);
// accumulate total status, the worst status has priority
if (eAllStatus > eStatus)
if (m_eStatus > eStatus)
{
eAllStatus = eStatus;
m_eStatus = eStatus;
}
if (g_pOptions->GetCreateBrokenLog())
@@ -536,7 +280,7 @@ ParChecker::EStatus ParChecker::RunParCheckAll()
free(szParFilename);
}
return eAllStatus;
Completed();
}
ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
@@ -547,7 +291,6 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
m_iProcessedFiles = 0;
m_iExtraFiles = 0;
m_bVerifyingExtraFiles = false;
m_bHasDamagedFiles = false;
EStatus eStatus = psFailed;
PrintMessage(Message::mkInfo, "Verifying %s", m_szInfoName);
@@ -573,7 +316,7 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
debug("ParChecker: Process-result=%i", res);
bool bAddedSplittedFragments = false;
if (m_bHasDamagedFiles && !IsStopped() && res == eRepairNotPossible)
if (!IsStopped() && res == eRepairNotPossible)
{
bAddedSplittedFragments = AddSplittedFragments();
if (bAddedSplittedFragments)
@@ -583,7 +326,7 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
}
}
if (m_bHasDamagedFiles && !IsStopped() && pRepairer->missingfilecount > 0 &&
if (!IsStopped() && pRepairer->missingfilecount > 0 &&
!(bAddedSplittedFragments && res == eRepairPossible) &&
g_pOptions->GetParScan() == Options::psAuto)
{
@@ -594,7 +337,7 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
}
}
if (m_bHasDamagedFiles && !IsStopped() && res == eRepairNotPossible)
if (!IsStopped() && res == eRepairNotPossible)
{
res = (Result)ProcessMorePars();
}
@@ -607,7 +350,7 @@ ParChecker::EStatus ParChecker::RunParCheck(const char* szParFilename)
eStatus = psFailed;
if (res == eSuccess || !m_bHasDamagedFiles)
if (res == eSuccess)
{
PrintMessage(Message::mkInfo, "Repair not needed for %s", m_szInfoName);
eStatus = psRepairNotNeeded;
@@ -679,8 +422,11 @@ int ParChecker::PreProcessPar()
{
Cleanup();
Repairer* pRepairer = new Repairer(this);
Repairer* pRepairer = new Repairer();
m_pRepairer = pRepairer;
pRepairer->sig_filename.connect(sigc::mem_fun(*this, &ParChecker::signal_filename));
pRepairer->sig_progress.connect(sigc::mem_fun(*this, &ParChecker::signal_progress));
pRepairer->sig_done.connect(sigc::mem_fun(*this, &ParChecker::signal_done));
res = pRepairer->PreProcess(m_szParFilename);
debug("ParChecker: PreProcess-result=%i", res);
@@ -1065,26 +811,14 @@ bool ParChecker::IsProcessedFile(const char* szFilename)
void ParChecker::signal_filename(std::string str)
{
if (!m_lastFilename.compare(str))
{
return;
}
m_lastFilename = str;
const char* szStageMessage[] = { "Loading file", "Verifying file", "Repairing file", "Verifying repaired file" };
const char* szStageMessage[] = { "Loading file", "Verifying file", "Repairing file", "Verifying repaired file" };
if (m_eStage == ptRepairing)
{
m_eStage = ptVerifyingRepaired;
}
// don't print progress messages when verifying repaired files in quick verification mode,
// because repaired files are not verified in this mode
if (!(m_eStage == ptVerifyingRepaired && m_bParQuick))
{
PrintMessage(Message::mkInfo, "%s %s", szStageMessage[m_eStage], str.c_str());
}
PrintMessage(Message::mkInfo, "%s %s", szStageMessage[m_eStage], str.c_str());
if (m_eStage == ptLoadingPars || m_eStage == ptVerifyingSources)
{
@@ -1152,14 +886,13 @@ void ParChecker::signal_done(std::string str, int available, int total)
{
if (available < total && !m_bVerifyingExtraFiles)
{
const char* szFilename = str.c_str();
bool bFileExists = true;
for (std::vector<Par2RepairerSourceFile*>::iterator it = ((Repairer*)m_pRepairer)->sourcefiles.begin();
it != ((Repairer*)m_pRepairer)->sourcefiles.end(); it++)
{
Par2RepairerSourceFile *sourcefile = *it;
if (sourcefile && !strcmp(szFilename, Util::BaseFileName(sourcefile->TargetFileName().c_str())) &&
if (sourcefile && !strcmp(str.c_str(), Util::BaseFileName(sourcefile->TargetFileName().c_str())) &&
!sourcefile->GetTargetExists())
{
bFileExists = false;
@@ -1167,19 +900,13 @@ void ParChecker::signal_done(std::string str, int available, int total)
}
}
bool bIgnore = Util::MatchFileExt(szFilename, g_pOptions->GetParIgnoreExt(), ",;") ||
Util::MatchFileExt(szFilename, g_pOptions->GetExtCleanupDisk(), ",;");
m_bHasDamagedFiles |= !bIgnore;
if (bFileExists)
{
PrintMessage(Message::mkWarning, "File %s has %i bad block(s) of total %i block(s)%s",
szFilename, total - available, total, bIgnore ? ", ignoring" : "");
PrintMessage(Message::mkWarning, "File %s has %i bad block(s) of total %i block(s)", str.c_str(), total - available, total);
}
else
{
PrintMessage(Message::mkWarning, "File %s with %i block(s) is missing%s",
szFilename, total, bIgnore ? ", ignoring" : "");
PrintMessage(Message::mkWarning, "File %s with %i block(s) is missing", str.c_str(), total);
}
}
}
@@ -1187,9 +914,13 @@ void ParChecker::signal_done(std::string str, int available, int total)
void ParChecker::Cancel()
{
#ifdef HAVE_PAR2_CANCEL
((Repairer*)m_pRepairer)->cancelled = true;
m_bCancelled = true;
QueueChanged();
#else
PrintMessage(Message::mkError, "Could not cancel par-repair. The program was compiled using version of libpar2 which doesn't support cancelling of par-repair. Please apply libpar2-patches supplied with NZBGet and recompile libpar2 and NZBGet (see README for details).");
#endif
}
void ParChecker::WriteBrokenLog(EStatus eStatus)
@@ -1287,324 +1018,4 @@ void ParChecker::DeleteLeftovers()
}
}
/**
* This function implements quick par verification replacing the standard verification routine
* from libpar2:
* - for successfully downloaded files the function compares CRC of the file computed during
* download with CRC stored in PAR2-file;
* - for partially downloaded files the CRCs of articles are compared with block-CRCs stored
* in PAR2-file;
* - for completely failed files (not a single successful artice) no verification is needed at all.
*
* Limitation of the function:
* This function requires every block in the file to have an unique CRC (across all blocks
* of the par-set). Otherwise the full verification is performed.
* The limitation can be avoided by using something more smart than "verificationhashtable.Lookup"
* but in the real life all blocks have unique CRCs and the simple "Lookup" works good enough.
*/
ParChecker::EFileStatus ParChecker::VerifyDataFile(void* pDiskfile, void* pSourcefile, int* pAvailableBlocks)
{
if (m_eStage != ptVerifyingSources)
{
// skipping verification for repaired files, assuming the files were correctly repaired,
// the only reason for incorrect files after repair are hardware errors (memory, disk),
// but this isn't something NZBGet should care about.
return fsSuccess;
}
DiskFile* pDiskFile = (DiskFile*)pDiskfile;
Par2RepairerSourceFile* pSourceFile = (Par2RepairerSourceFile*)pSourcefile;
if (!pSourcefile || !pSourceFile->GetTargetExists())
{
return fsUnknown;
}
VerificationPacket* packet = pSourceFile->GetVerificationPacket();
if (!packet)
{
return fsUnknown;
}
std::string filename = pSourceFile->GetTargetFile()->FileName();
const char* szFilename = filename.c_str();
if (Util::FileSize(szFilename) == 0 && pSourceFile->BlockCount() > 0)
{
*pAvailableBlocks = 0;
return fsFailure;
}
// find file status and CRC computed during download
unsigned long lDownloadCrc;
SegmentList segments;
EFileStatus eFileStatus = FindFileCrc(Util::BaseFileName(szFilename), &lDownloadCrc, &segments);
ValidBlocks validBlocks;
if (eFileStatus == fsFailure || eFileStatus == fsUnknown)
{
return eFileStatus;
}
else if ((eFileStatus == fsSuccess && !VerifySuccessDataFile(pDiskfile, pSourcefile, lDownloadCrc)) ||
(eFileStatus == fsPartial && !VerifyPartialDataFile(pDiskfile, pSourcefile, &segments, &validBlocks)))
{
PrintMessage(Message::mkWarning, "Quick verification failed for %s file %s, performing full verification instead",
eFileStatus == fsSuccess ? "good" : "damaged", Util::BaseFileName(szFilename));
return fsUnknown; // let libpar2 do the full verification of the file
}
// attach verification blocks to the file
*pAvailableBlocks = 0;
u64 blocksize = ((Repairer*)m_pRepairer)->mainpacket->BlockSize();
std::deque<const VerificationHashEntry*> undoList;
for (unsigned int i = 0; i < packet->BlockCount(); i++)
{
if (eFileStatus == fsSuccess || validBlocks.at(i))
{
const FILEVERIFICATIONENTRY* entry = packet->VerificationEntry(i);
u32 blockCrc = entry->crc;
// Look for a match
const VerificationHashEntry* pHashEntry = ((Repairer*)m_pRepairer)->verificationhashtable.Lookup(blockCrc);
if (!pHashEntry || pHashEntry->SourceFile() != pSourceFile || pHashEntry->IsSet())
{
// no match found, revert back the changes made by "pHashEntry->SetBlock"
for (std::deque<const VerificationHashEntry*>::iterator it = undoList.begin(); it != undoList.end(); it++)
{
const VerificationHashEntry* pUndoEntry = *it;
pUndoEntry->SetBlock(NULL, 0);
}
return fsUnknown;
}
undoList.push_back(pHashEntry);
pHashEntry->SetBlock(pDiskFile, i*blocksize);
(*pAvailableBlocks)++;
}
}
PrintMessage(Message::mkDetail, "Quickly verified %s file %s",
eFileStatus == fsSuccess ? "good" : "damaged", Util::BaseFileName(szFilename));
return eFileStatus;
}
bool ParChecker::VerifySuccessDataFile(void* pDiskfile, void* pSourcefile, unsigned long lDownloadCrc)
{
Par2RepairerSourceFile* pSourceFile = (Par2RepairerSourceFile*)pSourcefile;
u64 blocksize = ((Repairer*)m_pRepairer)->mainpacket->BlockSize();
VerificationPacket* packet = pSourceFile->GetVerificationPacket();
// extend lDownloadCrc to block size
lDownloadCrc = CRCUpdateBlock(lDownloadCrc ^ 0xFFFFFFFF,
(size_t)(blocksize * packet->BlockCount() > pSourceFile->GetTargetFile()->FileSize() ?
blocksize * packet->BlockCount() - pSourceFile->GetTargetFile()->FileSize() : 0)
) ^ 0xFFFFFFFF;
debug("Download-CRC: %.8x", lDownloadCrc);
// compute file CRC using CRCs of blocks
unsigned long lParCrc = 0;
for (unsigned int i = 0; i < packet->BlockCount(); i++)
{
const FILEVERIFICATIONENTRY* entry = packet->VerificationEntry(i);
u32 blockCrc = entry->crc;
lParCrc = i == 0 ? blockCrc : Util::Crc32Combine(lParCrc, blockCrc, (unsigned long)blocksize);
}
debug("Block-CRC: %x, filename: %s", lParCrc, Util::BaseFileName(pSourceFile->GetTargetFile()->FileName().c_str()));
return lParCrc == lDownloadCrc;
}
bool ParChecker::VerifyPartialDataFile(void* pDiskfile, void* pSourcefile, SegmentList* pSegments, ValidBlocks* pValidBlocks)
{
Par2RepairerSourceFile* pSourceFile = (Par2RepairerSourceFile*)pSourcefile;
VerificationPacket* packet = pSourceFile->GetVerificationPacket();
long long blocksize = ((Repairer*)m_pRepairer)->mainpacket->BlockSize();
std::string filename = pSourceFile->GetTargetFile()->FileName();
const char* szFilename = filename.c_str();
long long iFileSize = pSourceFile->GetTargetFile()->FileSize();
// determine presumably valid and bad blocks based on article download status
pValidBlocks->resize(packet->BlockCount(), false);
for (int i = 0; i < (int)pValidBlocks->size(); i++)
{
long long blockStart = i * blocksize;
long long blockEnd = blockStart + blocksize < iFileSize - 1 ? blockStart + blocksize : iFileSize - 1;
bool bBlockOK = false;
bool bBlockEnd = false;
u64 iCurOffset = 0;
for (SegmentList::iterator it = pSegments->begin(); it != pSegments->end(); it++)
{
Segment* pSegment = *it;
if (!bBlockOK && pSegment->GetSuccess() && pSegment->GetOffset() <= blockStart &&
pSegment->GetOffset() + pSegment->GetSize() >= blockStart)
{
bBlockOK = true;
iCurOffset = pSegment->GetOffset();
}
if (bBlockOK)
{
if (!(pSegment->GetSuccess() && pSegment->GetOffset() == iCurOffset))
{
bBlockOK = false;
break;
}
if (pSegment->GetOffset() + pSegment->GetSize() >= blockEnd)
{
bBlockEnd = true;
break;
}
iCurOffset = pSegment->GetOffset() + pSegment->GetSize();
}
}
pValidBlocks->at(i) = bBlockOK && bBlockEnd;
}
char szErrBuf[256];
FILE* infile = fopen(szFilename, FOPEN_RB);
if (!infile)
{
error("Could not open file %s: %s", szFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
// For each sequential range of presumably valid blocks:
// - compute par-CRC of the range of blocks using block CRCs;
// - compute download-CRC for the same byte range using CRCs of articles; if articles and block
// overlap - read a little bit of data from the file and calculate its CRC;
// - compare two CRCs - they must match; if not - the file is more damaged than we thought -
// let libpar2 do the full verification of the file in this case.
unsigned long lParCrc = 0;
int iBlockStart = -1;
pValidBlocks->push_back(false); // end marker
for (int i = 0; i < (int)pValidBlocks->size(); i++)
{
bool bValidBlock = pValidBlocks->at(i);
if (bValidBlock)
{
if (iBlockStart == -1)
{
iBlockStart = i;
}
const FILEVERIFICATIONENTRY* entry = packet->VerificationEntry(i);
u32 blockCrc = entry->crc;
lParCrc = iBlockStart == i ? blockCrc : Util::Crc32Combine(lParCrc, blockCrc, (unsigned long)blocksize);
}
else
{
if (iBlockStart > -1)
{
int iBlockEnd = i - 1;
long long iBytesStart = iBlockStart * blocksize;
long long iBytesEnd = iBlockEnd * blocksize + blocksize - 1;
unsigned long lDownloadCrc = 0;
bool bOK = SmartCalcFileRangeCrc(infile, iBytesStart,
iBytesEnd < iFileSize - 1 ? iBytesEnd : iFileSize - 1, pSegments, &lDownloadCrc);
if (bOK && iBytesEnd > iFileSize - 1)
{
// for the last block: extend lDownloadCrc to block size
lDownloadCrc = CRCUpdateBlock(lDownloadCrc ^ 0xFFFFFFFF, (size_t)(iBytesEnd - (iFileSize - 1))) ^ 0xFFFFFFFF;
}
if (!bOK || lDownloadCrc != lParCrc)
{
fclose(infile);
return false;
}
}
iBlockStart = -1;
}
}
fclose(infile);
return true;
}
/*
* Compute CRC of bytes range of file using CRCs of segments and reading some data directly
* from file if necessary
*/
bool ParChecker::SmartCalcFileRangeCrc(FILE* pFile, long long lStart, long long lEnd, SegmentList* pSegments,
unsigned long* pDownloadCrc)
{
unsigned long lDownloadCrc = 0;
bool bStarted = false;
for (SegmentList::iterator it = pSegments->begin(); it != pSegments->end(); it++)
{
Segment* pSegment = *it;
if (!bStarted && pSegment->GetOffset() > lStart)
{
// read start of range from file
if (!DumbCalcFileRangeCrc(pFile, lStart, pSegment->GetOffset() - 1, &lDownloadCrc))
{
return false;
}
if (pSegment->GetOffset() + pSegment->GetSize() >= lEnd)
{
break;
}
bStarted = true;
}
if (pSegment->GetOffset() >= lStart && pSegment->GetOffset() + pSegment->GetSize() <= lEnd)
{
lDownloadCrc = !bStarted ? pSegment->GetCrc() : Util::Crc32Combine(lDownloadCrc, pSegment->GetCrc(), (unsigned long)pSegment->GetSize());
bStarted = true;
}
if (pSegment->GetOffset() + pSegment->GetSize() == lEnd)
{
break;
}
if (pSegment->GetOffset() + pSegment->GetSize() > lEnd)
{
// read end of range from file
unsigned long lPartialCrc = 0;
if (!DumbCalcFileRangeCrc(pFile, pSegment->GetOffset(), lEnd, &lPartialCrc))
{
return false;
}
lDownloadCrc = Util::Crc32Combine(lDownloadCrc, (unsigned long)lPartialCrc, (unsigned long)(lEnd - pSegment->GetOffset() + 1));
break;
}
}
*pDownloadCrc = lDownloadCrc;
return true;
}
/*
* Compute CRC of bytes range of file reading the data directly from file
*/
bool ParChecker::DumbCalcFileRangeCrc(FILE* pFile, long long lStart, long long lEnd, unsigned long* pDownloadCrc)
{
if (fseek(pFile, lStart, SEEK_SET))
{
return false;
}
static const int BUFFER_SIZE = 1024 * 64;
unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE);
unsigned long lDownloadCrc = 0xFFFFFFFF;
int cnt = BUFFER_SIZE;
while (cnt == BUFFER_SIZE && lStart < lEnd)
{
int iNeedBytes = lEnd - lStart + 1 > BUFFER_SIZE ? BUFFER_SIZE : (int)(lEnd - lStart + 1);
cnt = (int)fread(buffer, 1, iNeedBytes, pFile);
lDownloadCrc = Util::Crc32m(lDownloadCrc, buffer, cnt);
lStart += cnt;
}
free(buffer);
lDownloadCrc ^= 0xFFFFFFFF;
*pDownloadCrc = lDownloadCrc;
return true;
}
#endif

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 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,7 +29,6 @@
#ifndef DISABLE_PARCHECK
#include <deque>
#include <vector>
#include <string>
#include "Thread.h"
@@ -54,43 +53,8 @@ public:
ptVerifyingRepaired,
};
enum EFileStatus
{
fsUnknown,
fsSuccess,
fsPartial,
fsFailure
};
class Segment
{
private:
bool m_bSuccess;
long long m_iOffset;
int m_iSize;
unsigned long m_lCrc;
public:
Segment(bool bSuccess, long long iOffset, int iSize, unsigned long lCrc);
bool GetSuccess() { return m_bSuccess; }
long long GetOffset() { return m_iOffset; }
int GetSize() { return m_iSize; }
unsigned long GetCrc() { return m_lCrc; }
};
typedef std::deque<Segment*> SegmentListBase;
class SegmentList : public SegmentListBase
{
public:
~SegmentList();
};
typedef std::deque<char*> FileList;
typedef std::deque<void*> SourceList;
typedef std::vector<bool> ValidBlocks;
friend class Repairer;
private:
char* m_szInfoName;
@@ -99,8 +63,7 @@ private:
const char* m_szParFilename;
EStatus m_eStatus;
EStage m_eStage;
// declared as void* to prevent the including of libpar2-headers into this header-file
void* m_pRepairer;
void* m_pRepairer; // declared as void* to prevent the including of libpar2-headers into this header-file
char* m_szErrMsg;
FileList m_QueuedParFiles;
Mutex m_mutexQueuedParFiles;
@@ -115,13 +78,8 @@ private:
int m_iStageProgress;
bool m_bCancelled;
SourceList m_sourceFiles;
std::string m_lastFilename;
bool m_bHasDamagedFiles;
bool m_bParQuick;
bool m_bForceRepair;
void Cleanup();
EStatus RunParCheckAll();
EStatus RunParCheck(const char* szParFilename);
int PreProcessPar();
bool LoadMainParBak();
@@ -136,14 +94,6 @@ private:
void signal_filename(std::string str);
void signal_progress(double progress);
void signal_done(std::string str, int available, int total);
// declared as void* to prevent the including of libpar2-headers into this header-file
// DiskFile* pDiskfile, Par2RepairerSourceFile* pSourcefile
EFileStatus VerifyDataFile(void* pDiskfile, void* pSourcefile, int* pAvailableBlocks);
bool VerifySuccessDataFile(void* pDiskfile, void* pSourcefile, unsigned long lDownloadCrc);
bool VerifyPartialDataFile(void* pDiskfile, void* pSourcefile, SegmentList* pSegments, ValidBlocks* pValidBlocks);
bool SmartCalcFileRangeCrc(FILE* pFile, long long lStart, long long lEnd, SegmentList* pSegments,
unsigned long* pDownloadCrc);
bool DumbCalcFileRangeCrc(FILE* pFile, long long lStart, long long lEnd, unsigned long* pDownloadCrc);
protected:
/**
@@ -157,7 +107,6 @@ protected:
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...) {}
virtual void RegisterParredFile(const char* szFilename) {}
virtual bool IsParredFile(const char* szFilename) { return false; }
virtual EFileStatus FindFileCrc(const char* szFilename, unsigned long* lCrc, SegmentList* pSegments) { return fsUnknown; }
EStage GetStage() { return m_eStage; }
const char* GetProgressLabel() { return m_szProgressLabel; }
int GetFileProgress() { return m_iFileProgress; }
@@ -172,10 +121,6 @@ public:
const char* GetInfoName() { return m_szInfoName; }
void SetInfoName(const char* szInfoName);
void SetNZBName(const char* szNZBName);
void SetParQuick(bool bParQuick) { m_bParQuick = bParQuick; }
bool GetParQuick() { return m_bParQuick; }
void SetForceRepair(bool bForceRepair) { m_bForceRepair = bForceRepair; }
bool GetForceRepair() { return m_bForceRepair; }
EStatus GetStatus() { return m_eStatus; }
void AddParFile(const char* szParFilename);
void QueueChanged();

View File

@@ -45,12 +45,10 @@
#include "nzbget.h"
#include "ParCoordinator.h"
#include "Options.h"
#include "DiskState.h"
#include "Log.h"
#include "Util.h"
extern Options* g_pOptions;
extern DiskState* g_pDiskState;
#ifndef DISABLE_PARCHECK
bool ParCoordinator::PostParChecker::RequestMorePars(int iBlockNeeded, int* pBlockFound)
@@ -93,59 +91,6 @@ bool ParCoordinator::PostParChecker::IsParredFile(const char* szFilename)
return false;
}
ParChecker::EFileStatus ParCoordinator::PostParChecker::FindFileCrc(const char* szFilename,
unsigned long* lCrc, SegmentList* pSegments)
{
CompletedFile* pCompletedFile = NULL;
for (CompletedFiles::iterator it = m_pPostInfo->GetNZBInfo()->GetCompletedFiles()->begin(); it != m_pPostInfo->GetNZBInfo()->GetCompletedFiles()->end(); it++)
{
CompletedFile* pCompletedFile2 = *it;
if (!strcasecmp(pCompletedFile2->GetFileName(), szFilename))
{
pCompletedFile = pCompletedFile2;
break;
}
}
if (!pCompletedFile)
{
return ParChecker::fsUnknown;
}
debug("Found completed file: %s, CRC: %.8x, Status: %i", Util::BaseFileName(pCompletedFile->GetFileName()), pCompletedFile->GetCrc(), (int)pCompletedFile->GetStatus());
*lCrc = pCompletedFile->GetCrc();
if (pCompletedFile->GetStatus() == CompletedFile::cfPartial && pCompletedFile->GetID() > 0 &&
!m_pPostInfo->GetNZBInfo()->GetReprocess())
{
FileInfo* pTmpFileInfo = new FileInfo(pCompletedFile->GetID());
if (!g_pDiskState->LoadFileState(pTmpFileInfo, NULL, true))
{
delete pTmpFileInfo;
return ParChecker::fsUnknown;
}
for (FileInfo::Articles::iterator it = pTmpFileInfo->GetArticles()->begin(); it != pTmpFileInfo->GetArticles()->end(); it++)
{
ArticleInfo* pa = *it;
ParChecker::Segment* pSegment = new Segment(pa->GetStatus() == ArticleInfo::aiFinished,
pa->GetSegmentOffset(), pa->GetSegmentSize(), pa->GetCrc());
pSegments->push_back(pSegment);
}
delete pTmpFileInfo;
}
return pCompletedFile->GetStatus() == CompletedFile::cfSuccess ? ParChecker::fsSuccess :
pCompletedFile->GetStatus() == CompletedFile::cfFailure &&
!m_pPostInfo->GetNZBInfo()->GetReprocess() ? ParChecker::fsFailure :
pCompletedFile->GetStatus() == CompletedFile::cfPartial && pSegments->size() > 0 &&
!m_pPostInfo->GetNZBInfo()->GetReprocess()? ParChecker::fsPartial :
ParChecker::fsUnknown;
}
void ParCoordinator::PostParRenamer::UpdateProgress()
{
m_pOwner->UpdateParRenameProgress();
@@ -168,22 +113,6 @@ void ParCoordinator::PostParRenamer::RegisterParredFile(const char* szFilename)
m_pPostInfo->GetParredFiles()->push_back(strdup(szFilename));
}
/**
* Update file name in the CompletedFiles-list of NZBInfo
*/
void ParCoordinator::PostParRenamer::RegisterRenamedFile(const char* szOldFilename, const char* szNewFileName)
{
for (CompletedFiles::iterator it = m_pPostInfo->GetNZBInfo()->GetCompletedFiles()->begin(); it != m_pPostInfo->GetNZBInfo()->GetCompletedFiles()->end(); it++)
{
CompletedFile* pCompletedFile = *it;
if (!strcasecmp(pCompletedFile->GetFileName(), szOldFilename))
{
pCompletedFile->SetFileName(szNewFileName);
break;
}
}
}
#endif
ParCoordinator::ParCoordinator()
@@ -351,10 +280,6 @@ void ParCoordinator::StartParCheckJob(PostInfo* pPostInfo)
m_ParChecker.SetPostInfo(pPostInfo);
m_ParChecker.SetDestDir(pPostInfo->GetNZBInfo()->GetDestDir());
m_ParChecker.SetNZBName(pPostInfo->GetNZBInfo()->GetName());
m_ParChecker.SetParTime(time(NULL));
m_ParChecker.SetDownloadSec(pPostInfo->GetNZBInfo()->GetDownloadSec());
m_ParChecker.SetParQuick(g_pOptions->GetParQuick() && !pPostInfo->GetForceParFull());
m_ParChecker.SetForceRepair(pPostInfo->GetForceRepair());
m_ParChecker.PrintMessage(Message::mkInfo, "Checking pars for %s", pPostInfo->GetNZBInfo()->GetName());
pPostInfo->SetWorking(true);
m_ParChecker.Start();
@@ -389,12 +314,16 @@ bool ParCoordinator::Cancel()
{
if (m_eCurrentJob == jkParCheck)
{
#ifdef HAVE_PAR2_CANCEL
if (!m_ParChecker.GetCancelled())
{
debug("Cancelling par-repair for %s", m_ParChecker.GetInfoName());
m_ParChecker.Cancel();
return true;
}
#else
warn("Cannot cancel par-repair for %s, used version of libpar2 does not support cancelling", m_ParChecker.GetInfoName());
#endif
}
else if (m_eCurrentJob == jkParRename)
{
@@ -452,13 +381,6 @@ void ParCoordinator::ParCheckCompleted()
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psFailure);
}
int iWaitTime = pPostInfo->GetNZBInfo()->GetDownloadSec() - m_ParChecker.GetDownloadSec();
pPostInfo->SetStartTime(pPostInfo->GetStartTime() + (time_t)iWaitTime);
int iParSec = (int)(time(NULL) - m_ParChecker.GetParTime()) - iWaitTime;
pPostInfo->GetNZBInfo()->SetParSec(pPostInfo->GetNZBInfo()->GetParSec() + iParSec);
pPostInfo->GetNZBInfo()->SetParFull(!m_ParChecker.GetParQuick());
pPostInfo->SetWorking(false);
pPostInfo->SetStage(PostInfo::ptQueued);
@@ -665,22 +587,19 @@ void ParCoordinator::UpdateParCheckProgress()
PostInfo::EStage eStage = StageKind[m_ParChecker.GetStage()];
time_t tCurrent = time(NULL);
if (!pPostInfo->GetStartTime())
{
pPostInfo->SetStartTime(tCurrent);
}
if (pPostInfo->GetStage() != eStage)
{
pPostInfo->SetStage(eStage);
pPostInfo->SetStageTime(tCurrent);
if (pPostInfo->GetStage() == PostInfo::ptRepairing)
{
m_ParChecker.SetRepairTime(tCurrent);
}
else if (pPostInfo->GetStage() == PostInfo::ptVerifyingRepaired)
{
int iRepairSec = (int)(tCurrent - m_ParChecker.GetRepairTime());
pPostInfo->GetNZBInfo()->SetRepairSec(pPostInfo->GetNZBInfo()->GetRepairSec() + iRepairSec);
}
}
bool bParCancel = false;
#ifdef HAVE_PAR2_CANCEL
if (!m_ParChecker.GetCancelled())
{
if ((g_pOptions->GetParTimeLimit() > 0) &&
@@ -699,6 +618,7 @@ void ParCoordinator::UpdateParCheckProgress()
}
}
}
#endif
if (bParCancel)
{
@@ -716,14 +636,12 @@ void ParCoordinator::CheckPauseState(PostInfo* pPostInfo)
{
time_t tStageTime = pPostInfo->GetStageTime();
time_t tStartTime = pPostInfo->GetStartTime();
time_t tParTime = m_ParChecker.GetParTime();
time_t tRepairTime = m_ParChecker.GetRepairTime();
time_t tWaitTime = time(NULL);
// wait until Post-processor is unpaused
while (g_pOptions->GetPausePostProcess() && !pPostInfo->GetNZBInfo()->GetForcePriority() && !m_bStopped)
{
usleep(50 * 1000);
usleep(100 * 1000);
// update time stamps
@@ -733,18 +651,11 @@ void ParCoordinator::CheckPauseState(PostInfo* pPostInfo)
{
pPostInfo->SetStageTime(tStageTime + tDelta);
}
if (tStartTime > 0)
{
pPostInfo->SetStartTime(tStartTime + tDelta);
}
if (tParTime > 0)
{
m_ParChecker.SetParTime(tParTime + tDelta);
}
if (tRepairTime > 0)
{
m_ParChecker.SetRepairTime(tRepairTime + tDelta);
}
}
}
}
@@ -761,6 +672,11 @@ void ParCoordinator::ParRenameCompleted()
PrintMessage(pPostInfo, Message::mkInfo, "Requesting par-check/repair for %s to restore missing files ", m_ParRenamer.GetInfoName());
pPostInfo->SetRequestParCheck(true);
}
else if (m_ParRenamer.HasSplittedFragments() && pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped)
{
PrintMessage(pPostInfo, Message::mkInfo, "Requesting par-check/repair for %s to join splitted fragments", m_ParRenamer.GetInfoName());
pPostInfo->SetRequestParCheck(true);
}
pPostInfo->SetWorking(false);
pPostInfo->SetStage(PostInfo::ptQueued);
@@ -779,6 +695,11 @@ void ParCoordinator::UpdateParRenameProgress()
pPostInfo->SetStageProgress(m_ParRenamer.GetStageProgress());
time_t tCurrent = time(NULL);
if (!pPostInfo->GetStartTime())
{
pPostInfo->SetStartTime(tCurrent);
}
if (pPostInfo->GetStage() != PostInfo::ptRenaming)
{
pPostInfo->SetStage(PostInfo::ptRenaming);

View File

@@ -45,9 +45,6 @@ private:
private:
ParCoordinator* m_pOwner;
PostInfo* m_pPostInfo;
time_t m_tParTime;
time_t m_tRepairTime;
int m_iDownloadSec;
protected:
virtual bool RequestMorePars(int iBlockNeeded, int* pBlockFound);
virtual void UpdateProgress();
@@ -55,16 +52,9 @@ private:
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...);
virtual void RegisterParredFile(const char* szFilename);
virtual bool IsParredFile(const char* szFilename);
virtual EFileStatus FindFileCrc(const char* szFilename, unsigned long* lCrc, SegmentList* pSegments);
public:
PostInfo* GetPostInfo() { return m_pPostInfo; }
void SetPostInfo(PostInfo* pPostInfo) { m_pPostInfo = pPostInfo; }
time_t GetParTime() { return m_tParTime; }
void SetParTime(time_t tParTime) { m_tParTime = tParTime; }
time_t GetRepairTime() { return m_tRepairTime; }
void SetRepairTime(time_t tRepairTime) { m_tRepairTime = tRepairTime; }
int GetDownloadSec() { return m_iDownloadSec; }
void SetDownloadSec(int iDownloadSec) { m_iDownloadSec = iDownloadSec; }
friend class ParCoordinator;
};
@@ -79,7 +69,6 @@ private:
virtual void Completed() { m_pOwner->ParRenameCompleted(); }
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...);
virtual void RegisterParredFile(const char* szFilename);
virtual void RegisterRenamedFile(const char* szOldFilename, const char* szNewFileName);
public:
PostInfo* GetPostInfo() { return m_pPostInfo; }
void SetPostInfo(PostInfo* pPostInfo) { m_pPostInfo = pPostInfo; }

View File

@@ -37,14 +37,17 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#ifndef WIN32
#ifdef WIN32
#include <par2cmdline.h>
#include <par2repairer.h>
#include <md5.h>
#else
#include <unistd.h>
#include <libpar2/par2cmdline.h>
#include <libpar2/par2repairer.h>
#include <libpar2/md5.h>
#endif
#include "par2cmdline.h"
#include "par2repairer.h"
#include "md5.h"
#include "nzbget.h"
#include "ParRenamer.h"
#include "ParCoordinator.h"
@@ -83,6 +86,7 @@ ParRenamer::ParRenamer()
m_szProgressLabel = (char*)malloc(1024);
m_iStageProgress = 0;
m_bCancelled = false;
m_bHasSplittedFragments = false;
m_bHasMissedFiles = false;
m_bDetectMissing = false;
}
@@ -142,6 +146,7 @@ void ParRenamer::Run()
m_iFileCount = 0;
m_iCurFile = 0;
m_iRenamedCount = 0;
m_bHasSplittedFragments = false;
m_bHasMissedFiles = false;
m_eStatus = psFailed;
@@ -339,10 +344,12 @@ bool ParRenamer::IsSplittedFragment(const char* szFilename, const char* szCorrec
{
for (p++; *p && strchr("0123456789", *p); p++) ;
bSplittedFragement = !*p;
bSplittedFragement = bSplittedFragement && atoi(szDiskBasename + iBaseLen + 1) <= 1; // .000 or .001
bSplittedFragement = bSplittedFragement && atoi(szDiskBasename + iBaseLen + 1) == 1;
}
}
m_bHasSplittedFragments = m_bHasSplittedFragments || bSplittedFragement;
return bSplittedFragement;
}
@@ -396,7 +403,17 @@ void ParRenamer::CheckRegularFile(const char* szDestDir, const char* szFilename)
if (!Util::FileExists(szDstFilename) && !IsSplittedFragment(szFilename, pFileHash->GetFilename()))
{
RenameFile(szFilename, szDstFilename);
PrintMessage(Message::mkInfo, "Renaming %s to %s", Util::BaseFileName(szFilename), pFileHash->GetFilename());
if (Util::MoveFile(szFilename, szDstFilename))
{
m_iRenamedCount++;
}
else
{
char szErrBuf[256];
PrintMessage(Message::mkError, "Could not rename %s to %s: %s", szFilename, szDstFilename,
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
}
}
break;
@@ -466,24 +483,17 @@ void ParRenamer::CheckParFile(const char* szDestDir, const char* szFilename)
iNum++;
}
RenameFile(szFilename, szDestFileName);
}
void ParRenamer::RenameFile(const char* szSrcFilename, const char* szDestFileName)
{
PrintMessage(Message::mkInfo, "Renaming %s to %s", Util::BaseFileName(szSrcFilename), Util::BaseFileName(szDestFileName));
if (!Util::MoveFile(szSrcFilename, szDestFileName))
PrintMessage(Message::mkInfo, "Renaming %s to %s", Util::BaseFileName(szFilename), Util::BaseFileName(szDestFileName));
if (Util::MoveFile(szFilename, szDestFileName))
{
m_iRenamedCount++;
}
else
{
char szErrBuf[256];
PrintMessage(Message::mkError, "Could not rename %s to %s: %s", szSrcFilename, szDestFileName,
PrintMessage(Message::mkError, "Could not rename %s to %s: %s", szFilename, szDestFileName,
Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
return;
}
m_iRenamedCount++;
// notify about new file name
RegisterRenamedFile(Util::BaseFileName(szSrcFilename), Util::BaseFileName(szDestFileName));
}
#endif

View File

@@ -59,6 +59,7 @@ public:
};
typedef std::deque<FileHash*> FileHashList;
typedef std::deque<char*> DirList;
private:
@@ -73,6 +74,7 @@ private:
int m_iFileCount;
int m_iCurFile;
int m_iRenamedCount;
bool m_bHasSplittedFragments;
bool m_bHasMissedFiles;
bool m_bDetectMissing;
@@ -87,14 +89,12 @@ private:
void CheckParFile(const char* szDestDir, const char* szFilename);
bool IsSplittedFragment(const char* szFilename, const char* szCorrectName);
void CheckMissing();
void RenameFile(const char* szSrcFilename, const char* szDestFileName);
protected:
virtual void UpdateProgress() {}
virtual void Completed() {}
virtual void PrintMessage(Message::EKind eKind, const char* szFormat, ...) {}
virtual void RegisterParredFile(const char* szFilename) {}
virtual void RegisterRenamedFile(const char* szOldFilename, const char* szNewFileName) {}
const char* GetProgressLabel() { return m_szProgressLabel; }
int GetStageProgress() { return m_iStageProgress; }
@@ -109,6 +109,7 @@ public:
EStatus GetStatus() { return m_eStatus; }
void Cancel();
bool GetCancelled() { return m_bCancelled; }
bool HasSplittedFragments() { return m_bHasSplittedFragments; }
bool HasMissedFiles() { return m_bHasMissedFiles; }
void SetDetectMissing(bool bDetectMissing) { m_bDetectMissing = bDetectMissing; }
};

View File

@@ -112,7 +112,6 @@ void PostScriptController::ExecuteScript(Options::Script* pScript)
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
m_pScript = pScript;
SetLogPrefix(pScript->GetDisplayName());
m_iPrefixLen = strlen(pScript->GetDisplayName()) + 2; // 2 = strlen(": ");
PrepareParams(pScript->GetName());
@@ -161,15 +160,7 @@ void PostScriptController::PrepareParams(const char* szScriptName)
// deprecated
int iParStatus[] = { 0, 0, 1, 2, 3, 4 };
NZBInfo::EParStatus eParStatus = m_pPostInfo->GetNZBInfo()->GetParStatus();
// for downloads marked as bad and for deleted downloads pass par status "Failure"
// for compatibility with older scripts which don't check "NZBPP_TOTALSTATUS"
if (m_pPostInfo->GetNZBInfo()->GetDeleteStatus() != NZBInfo::dsNone ||
m_pPostInfo->GetNZBInfo()->GetMarkStatus() == NZBInfo::ksBad)
{
eParStatus = NZBInfo::psFailure;
}
SetIntEnvVar("NZBPP_PARSTATUS", iParStatus[eParStatus]);
SetIntEnvVar("NZBPP_PARSTATUS", iParStatus[m_pPostInfo->GetNZBInfo()->GetParStatus()]);
// deprecated
int iUnpackStatus[] = { 0, 0, 1, 2, 3, 4 };
@@ -233,7 +224,6 @@ ScriptStatus::EStatus PostScriptController::AnalyseExitCode(int iExitCode)
{
PrintMessage(Message::mkInfo, "%s requested par-check/repair", GetInfoName());
m_pPostInfo->SetRequestParCheck(true);
m_pPostInfo->SetForceRepair(true);
return ScriptStatus::srSuccess;
}
break;
@@ -281,13 +271,6 @@ void PostScriptController::AddMessage(Message::EKind eKind, const char* szText)
}
free(szParam);
}
else if (!strncmp(szMsgText + 6, "MARK=BAD", 8))
{
SetLogPrefix(NULL);
PrintMessage(Message::mkWarning, "Marking %s as bad", m_pPostInfo->GetNZBInfo()->GetName());
SetLogPrefix(m_pScript->GetDisplayName());
m_pPostInfo->GetNZBInfo()->SetMarkStatus(NZBInfo::ksBad);
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());

View File

@@ -36,8 +36,8 @@ class PostScriptController : public Thread, public NZBScriptController
{
private:
PostInfo* m_pPostInfo;
char m_szNZBName[1024];
int m_iPrefixLen;
Options::Script* m_pScript;
void PrepareParams(const char* szScriptName);
ScriptStatus::EStatus AnalyseExitCode(int iExitCode);

View File

@@ -55,7 +55,6 @@
#include "Unpack.h"
#include "NZBFile.h"
#include "StatMeter.h"
#include "QueueScript.h"
extern HistoryCoordinator* g_pHistoryCoordinator;
extern DupeCoordinator* g_pDupeCoordinator;
@@ -63,7 +62,6 @@ extern Options* g_pOptions;
extern Scheduler* g_pScheduler;
extern Scanner* g_pScanner;
extern StatMeter* g_pStatMeter;
extern QueueScriptCoordinator* g_pQueueScriptCoordinator;
PrePostProcessor::PrePostProcessor()
{
@@ -190,25 +188,9 @@ void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect)
{
NZBAdded(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
}
else if (pQueueAspect->eAction == DownloadQueue::eaNzbDeleted &&
pQueueAspect->pNZBInfo->GetDeleting() &&
!pQueueAspect->pNZBInfo->GetPostInfo() &&
!pQueueAspect->pNZBInfo->GetParCleanup() &&
pQueueAspect->pNZBInfo->GetFileList()->empty())
{
// the deleting of nzbs is usually handled via eaFileDeleted-event, but when deleting nzb without
// any files left the eaFileDeleted-event is not fired and we need to process eaNzbDeleted-event instead
info("Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName());
NZBDeleted(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
}
else if ((pQueueAspect->eAction == DownloadQueue::eaFileCompleted ||
pQueueAspect->eAction == DownloadQueue::eaFileDeleted))
{
if (pQueueAspect->eAction == DownloadQueue::eaFileCompleted && !pQueueAspect->pNZBInfo->GetPostInfo())
{
g_pQueueScriptCoordinator->EnqueueScript(pQueueAspect->pNZBInfo, QueueScriptCoordinator::qeFileDownloaded);
}
if (
#ifndef DISABLE_PARCHECK
!m_ParCoordinator.AddPar(pQueueAspect->pFileInfo, pQueueAspect->eAction == DownloadQueue::eaFileDeleted) &&
@@ -223,7 +205,6 @@ void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect)
pQueueAspect->pFileInfo->GetNZBInfo()->GetDeleteStatus() != NZBInfo::dsHealth)
{
info("Collection %s completely downloaded", pQueueAspect->pNZBInfo->GetName());
g_pQueueScriptCoordinator->EnqueueScript(pQueueAspect->pNZBInfo, QueueScriptCoordinator::qeNzbDownloaded);
NZBDownloaded(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
}
else if ((pQueueAspect->eAction == DownloadQueue::eaFileDeleted ||
@@ -259,9 +240,9 @@ void PrePostProcessor::NZBAdded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo
{
NZBCompleted(pDownloadQueue, pNZBInfo, false);
}
else
else if (!Util::EmptyStr(g_pOptions->GetQueueScript()))
{
g_pQueueScriptCoordinator->EnqueueScript(pNZBInfo, QueueScriptCoordinator::qeNzbAdded);
QueueScriptController::StartScripts(pDownloadQueue, pNZBInfo);
}
}
@@ -286,6 +267,14 @@ void PrePostProcessor::NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
pNZBInfo->SetRenameStatus(NZBInfo::rsSkipped);
}
if (pNZBInfo->GetDeleteStatus() != NZBInfo::dsNone)
{
pNZBInfo->SetParStatus(NZBInfo::psFailure);
pNZBInfo->SetUnpackStatus(NZBInfo::usFailure);
pNZBInfo->SetRenameStatus(NZBInfo::rsFailure);
pNZBInfo->SetMoveStatus(NZBInfo::msFailure);
}
pDownloadQueue->Save();
}
else
@@ -302,70 +291,17 @@ void PrePostProcessor::NZBDeleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBIn
}
pNZBInfo->SetDeleting(false);
DeleteCleanup(pNZBInfo);
if (pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsBad)
{
NZBDownloaded(pDownloadQueue, pNZBInfo);
}
else
{
NZBCompleted(pDownloadQueue, pNZBInfo, true);
}
}
void PrePostProcessor::NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bSaveQueue)
{
bool bAddToHistory = g_pOptions->GetKeepHistory() > 0 && !pNZBInfo->GetAvoidHistory();
if (bAddToHistory)
{
g_pHistoryCoordinator->AddToHistory(pDownloadQueue, pNZBInfo);
}
pNZBInfo->SetAvoidHistory(false);
bool bNeedSave = bAddToHistory;
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce &&
(pNZBInfo->GetDeleteStatus() == NZBInfo::dsNone ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsBad))
{
g_pDupeCoordinator->NZBCompleted(pDownloadQueue, pNZBInfo);
bNeedSave = true;
}
if (!bAddToHistory)
{
g_pHistoryCoordinator->DeleteDiskFiles(pNZBInfo);
pDownloadQueue->GetQueue()->Remove(pNZBInfo);
delete pNZBInfo;
}
if (bSaveQueue && bNeedSave)
{
pDownloadQueue->Save();
}
}
void PrePostProcessor::DeleteCleanup(NZBInfo* pNZBInfo)
{
if ((g_pOptions->GetDeleteCleanupDisk() && pNZBInfo->GetCleanupDisk()) ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsDupe)
{
// download was cancelled, deleting already downloaded files from disk
for (CompletedFiles::reverse_iterator it = pNZBInfo->GetCompletedFiles()->rbegin(); it != pNZBInfo->GetCompletedFiles()->rend(); it++)
for (NZBInfo::Files::reverse_iterator it = pNZBInfo->GetCompletedFiles()->rbegin(); it != pNZBInfo->GetCompletedFiles()->rend(); it++)
{
CompletedFile* pCompletedFile = *it;
char szFullFileName[1024];
snprintf(szFullFileName, 1024, "%s%c%s", pNZBInfo->GetDestDir(), (int)PATH_SEPARATOR, pCompletedFile->GetFileName());
szFullFileName[1024-1] = '\0';
if (Util::FileExists(szFullFileName))
char* szFilename = *it;
if (Util::FileExists(szFilename))
{
detail("Deleting file %s", pCompletedFile->GetFileName());
remove(szFullFileName);
detail("Deleting file %s", Util::BaseFileName(szFilename));
remove(szFilename);
}
}
@@ -391,6 +327,47 @@ void PrePostProcessor::DeleteCleanup(NZBInfo* pNZBInfo)
rmdir(pNZBInfo->GetDestDir());
}
}
if (pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth)
{
NZBDownloaded(pDownloadQueue, pNZBInfo);
}
else
{
NZBCompleted(pDownloadQueue, pNZBInfo, true);
}
}
void PrePostProcessor::NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bSaveQueue)
{
bool bAddToHistory = g_pOptions->GetKeepHistory() > 0 && !pNZBInfo->GetAvoidHistory();
if (bAddToHistory)
{
g_pHistoryCoordinator->AddToHistory(pDownloadQueue, pNZBInfo);
}
pNZBInfo->SetAvoidHistory(false);
bool bNeedSave = bAddToHistory;
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce &&
(pNZBInfo->GetDeleteStatus() == NZBInfo::dsNone ||
pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth))
{
g_pDupeCoordinator->NZBCompleted(pDownloadQueue, pNZBInfo);
bNeedSave = true;
}
if (!bAddToHistory)
{
g_pHistoryCoordinator->DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
pDownloadQueue->GetQueue()->Remove(pNZBInfo);
delete pNZBInfo;
}
if (bSaveQueue && bNeedSave)
{
pDownloadQueue->Save();
}
}
void PrePostProcessor::CheckDiskSpace()
@@ -420,6 +397,11 @@ void PrePostProcessor::CheckPostQueue()
if (!m_pCurJob && m_iJobCount > 0)
{
m_pCurJob = GetNextJob(pDownloadQueue);
if (!m_pCurJob && !g_pOptions->GetPausePostProcess())
{
error("Internal error: no jobs found in queue");
m_iJobCount = 0;
}
}
if (m_pCurJob)
@@ -428,12 +410,9 @@ void PrePostProcessor::CheckPostQueue()
if (!pPostInfo->GetWorking() && !IsNZBFileDownloading(m_pCurJob))
{
#ifndef DISABLE_PARCHECK
if (pPostInfo->GetRequestParCheck() &&
(pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped ||
(pPostInfo->GetForceRepair() && !pPostInfo->GetNZBInfo()->GetParFull())) &&
if (pPostInfo->GetRequestParCheck() && pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped &&
g_pOptions->GetParCheck() != Options::pcManual)
{
pPostInfo->SetForceParFull(pPostInfo->GetNZBInfo()->GetParStatus() > NZBInfo::psSkipped);
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psNone);
pPostInfo->SetRequestParCheck(false);
pPostInfo->SetStage(PostInfo::ptQueued);
@@ -495,8 +474,7 @@ NZBInfo* PrePostProcessor::GetNextJob(DownloadQueue* pDownloadQueue)
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo1 = *it;
if (pNZBInfo1->GetPostInfo() && !g_pQueueScriptCoordinator->HasJob(pNZBInfo1->GetID()) &&
(!pNZBInfo || pNZBInfo1->GetPriority() > pNZBInfo->GetPriority()) &&
if (pNZBInfo1->GetPostInfo() && (!pNZBInfo || pNZBInfo1->GetPriority() > pNZBInfo->GetPriority()) &&
(!g_pOptions->GetPausePostProcess() || pNZBInfo1->GetForcePriority()))
{
pNZBInfo = pNZBInfo1;
@@ -541,21 +519,14 @@ void PrePostProcessor::DeletePostThread(PostInfo* pPostInfo)
void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo)
{
if (!pPostInfo->GetStartTime())
{
pPostInfo->SetStartTime(time(NULL));
}
#ifndef DISABLE_PARCHECK
if (pPostInfo->GetNZBInfo()->GetRenameStatus() == NZBInfo::rsNone &&
pPostInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsNone)
if (pPostInfo->GetNZBInfo()->GetRenameStatus() == NZBInfo::rsNone)
{
UpdatePauseState(g_pOptions->GetParPauseQueue(), "par-rename");
m_ParCoordinator.StartParRenameJob(pPostInfo);
return;
}
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psNone &&
pPostInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsNone)
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psNone)
{
if (m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
{
@@ -594,8 +565,7 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
NZBParameter* pUnpackParameter = pPostInfo->GetNZBInfo()->GetParameters()->Find("*Unpack:", false);
bool bUnpackParam = !(pUnpackParameter && !strcasecmp(pUnpackParameter->GetValue(), "no"));
bool bUnpack = bUnpackParam && pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usNone &&
pPostInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsNone;
bool bUnpack = bUnpackParam && (pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usNone);
bool bParFailed = pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psFailure ||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psRepairPossible ||
@@ -603,13 +573,10 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
bool bCleanup = !bUnpack &&
pPostInfo->GetNZBInfo()->GetCleanupStatus() == NZBInfo::csNone &&
((pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSuccess &&
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usFailure &&
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usSpace &&
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usPassword) ||
(pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSuccess ||
(pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usSuccess &&
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure)) &&
!Util::EmptyStr(g_pOptions->GetExtCleanupDisk());
strlen(g_pOptions->GetExtCleanupDisk()) > 0;
bool bMoveInter = !bUnpack &&
pPostInfo->GetNZBInfo()->GetMoveStatus() == NZBInfo::msNone &&
@@ -618,8 +585,7 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usPassword &&
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure &&
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psManual &&
pPostInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsNone &&
!Util::EmptyStr(g_pOptions->GetInterDir()) &&
strlen(g_pOptions->GetInterDir()) > 0 &&
!strncmp(pPostInfo->GetNZBInfo()->GetDestDir(), g_pOptions->GetInterDir(), strlen(g_pOptions->GetInterDir()));
bool bPostScript = true;
@@ -646,6 +612,10 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
pDownloadQueue->Save();
if (!pPostInfo->GetStartTime())
{
pPostInfo->SetStartTime(time(NULL));
}
pPostInfo->SetStageTime(time(NULL));
if (bUnpack)
@@ -673,44 +643,27 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn
void PrePostProcessor::JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo)
{
NZBInfo* pNZBInfo = pPostInfo->GetNZBInfo();
if (pPostInfo->GetStartTime() > 0)
{
pNZBInfo->SetPostTotalSec((int)(time(NULL) - pPostInfo->GetStartTime()));
pPostInfo->SetStartTime(0);
}
DeletePostThread(pPostInfo);
pNZBInfo->LeavePostProcess();
if (IsNZBFileCompleted(pNZBInfo, true, false))
{
// Cleaning up queue if par-check was successful or unpack was successful or
// health is 100% (if unpack and par-check were not performed)
// or health is below critical health
bool bCanCleanupQueue =
((pNZBInfo->GetParStatus() == NZBInfo::psSuccess ||
pNZBInfo->GetParStatus() == NZBInfo::psRepairPossible) &&
pNZBInfo->GetUnpackStatus() != NZBInfo::usFailure &&
pNZBInfo->GetUnpackStatus() != NZBInfo::usSpace &&
pNZBInfo->GetUnpackStatus() != NZBInfo::usPassword) ||
(pNZBInfo->GetUnpackStatus() == NZBInfo::usSuccess &&
pNZBInfo->GetParStatus() != NZBInfo::psFailure) ||
(pNZBInfo->GetUnpackStatus() <= NZBInfo::usSkipped &&
pNZBInfo->GetParStatus() != NZBInfo::psFailure &&
pNZBInfo->GetFailedSize() - pNZBInfo->GetParFailedSize() == 0) ||
(pNZBInfo->CalcHealth() < pNZBInfo->CalcCriticalHealth(false) &&
pNZBInfo->CalcCriticalHealth(false) < 1000);
if (g_pOptions->GetParCleanupQueue() && bCanCleanupQueue && !pNZBInfo->GetFileList()->empty())
// script was successful (if unpack was not performed)
bool bCanCleanupQueue = pNZBInfo->GetParStatus() == NZBInfo::psSuccess ||
pNZBInfo->GetParStatus() == NZBInfo::psRepairPossible ||
pNZBInfo->GetUnpackStatus() == NZBInfo::usSuccess ||
(pNZBInfo->GetUnpackStatus() == NZBInfo::usNone &&
pNZBInfo->GetScriptStatuses()->CalcTotalStatus() == ScriptStatus::srSuccess);
if (g_pOptions->GetParCleanupQueue() && bCanCleanupQueue)
{
info("Cleaning up download queue for %s", pNZBInfo->GetName());
pNZBInfo->SetParCleanup(true);
pDownloadQueue->EditEntry(pNZBInfo->GetID(), DownloadQueue::eaGroupDelete, 0, NULL);
}
if (pNZBInfo->GetUnpackCleanedUpDisk())
{
pNZBInfo->ClearCompletedFiles();
if (!pNZBInfo->GetFileList()->empty())
{
info("Cleaning up download queue for %s", pNZBInfo->GetName());
pNZBInfo->ClearCompletedFiles();
pNZBInfo->SetParCleanup(true);
pDownloadQueue->EditEntry(pNZBInfo->GetID(), DownloadQueue::eaGroupDelete, 0, NULL);
}
}
NZBCompleted(pDownloadQueue, pNZBInfo, false);

View File

@@ -60,13 +60,13 @@ private:
void CheckDiskSpace();
void UpdatePauseState(bool bNeedPause, const char* szReason);
void NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void NZBAdded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void NZBDeleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bSaveQueue);
bool PostQueueDelete(DownloadQueue* pDownloadQueue, IDList* pIDList);
void DeletePostThread(PostInfo* pPostInfo);
NZBInfo* GetNextJob(DownloadQueue* pDownloadQueue);
void DownloadQueueUpdate(Subject* Caller, void* Aspect);
void DeleteCleanup(NZBInfo* pNZBInfo);
public:
PrePostProcessor();
@@ -76,7 +76,6 @@ public:
bool HasMoreJobs() { return m_iJobCount > 0; }
int GetJobCount() { return m_iJobCount; }
bool EditList(DownloadQueue* pDownloadQueue, IDList* pIDList, DownloadQueue::EEditAction eAction, int iOffset, const char* szText);
void NZBAdded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
};

View File

@@ -85,8 +85,6 @@ void UnpackController::StartJob(PostInfo* pPostInfo)
void UnpackController::Run()
{
time_t tStart = time(NULL);
// the locking is needed for accessing the members of NZBInfo
DownloadQueue::Lock();
@@ -100,7 +98,7 @@ void UnpackController::Run()
m_szPassword[0] = '\0';
m_szFinalDir[0] = '\0';
m_bFinalDirCreated = false;
NZBParameter* pParameter = m_pPostInfo->GetNZBInfo()->GetParameters()->Find("*Unpack:", false);
bool bUnpack = !(pParameter && !strcasecmp(pParameter->GetValue(), "no"));
@@ -129,24 +127,20 @@ void UnpackController::Run()
CheckArchiveFiles(bScanNonStdFiles);
}
SetInfoName(m_szInfoName);
SetWorkingDir(m_szDestDir);
bool bHasFiles = m_bHasRarFiles || m_bHasNonStdRarFiles || m_bHasSevenZipFiles || m_bHasSevenZipMultiFiles || m_bHasSplittedFiles;
if (bUnpack && bHasFiles)
if (bUnpack && (m_bHasRarFiles || m_bHasNonStdRarFiles || m_bHasSevenZipFiles || m_bHasSevenZipMultiFiles))
{
m_bUnpackOK = true;
m_bUnpackStartError = false;
m_bUnpackSpaceError = false;
m_bUnpackPasswordError4 = false;
m_bUnpackPasswordError5 = false;
m_bAutoTerminated = false;
SetInfoName(m_szInfoName);
SetWorkingDir(m_szDestDir);
PrintMessage(Message::mkInfo, "Unpacking %s", m_szName);
CreateUnpackDir();
m_bUnpackOK = true;
m_bUnpackStartError = false;
m_bUnpackSpaceError = false;
m_bUnpackPasswordError = false;
if (m_bHasRarFiles || m_bHasNonStdRarFiles)
{
ExecuteUnrar();
@@ -162,14 +156,7 @@ void UnpackController::Run()
ExecuteSevenZip(true);
}
if (m_bHasSplittedFiles && m_bUnpackOK)
{
JoinSplittedFiles();
}
Completed();
m_JoinedFiles.Clear();
}
else
{
@@ -179,7 +166,7 @@ void UnpackController::Run()
if (bUnpack && m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped &&
m_pPostInfo->GetNZBInfo()->GetRenameStatus() <= NZBInfo::rsSkipped && m_bHasParFiles)
{
RequestParCheck(false);
RequestParCheck();
}
else
#endif
@@ -189,9 +176,6 @@ void UnpackController::Run()
}
}
int iUnpackSec = (int)(time(NULL) - tStart);
m_pPostInfo->GetNZBInfo()->SetUnpackSec(m_pPostInfo->GetNZBInfo()->GetUnpackSec() + iUnpackSec);
m_pPostInfo->SetWorking(false);
}
@@ -209,17 +193,11 @@ void UnpackController::ExecuteUnrar()
if (strlen(m_szPassword) > 0)
{
snprintf(szPasswordParam, 1024, "-p%s", m_szPassword);
szPasswordParam[1024-1] = '\0';
szArgs[3] = szPasswordParam;
}
szArgs[4] = "-o+";
szArgs[5] = m_bHasNonStdRarFiles ? "*.*" : "*.rar";
char szUnpackDirParam[1024];
snprintf(szUnpackDirParam, 1024, "%s%c", m_szUnpackDir, PATH_SEPARATOR);
szUnpackDirParam[1024-1] = '\0';
szArgs[6] = szUnpackDirParam;
szArgs[6] = m_szUnpackDir;
szArgs[7] = NULL;
SetArgs(szArgs, false);
@@ -237,7 +215,7 @@ void UnpackController::ExecuteUnrar()
m_bUnpackOK = iExitCode == 0 && m_bAllOKMessageReceived && !GetTerminated();
m_bUnpackStartError = iExitCode == -1;
m_bUnpackSpaceError = iExitCode == 5;
m_bUnpackPasswordError5 |= iExitCode == 11; // only for rar5-archives
m_bUnpackPasswordError = iExitCode == 11; // only for rar5-archives
if (!m_bUnpackOK && iExitCode > 0)
{
@@ -262,13 +240,11 @@ void UnpackController::ExecuteSevenZip(bool bMultiVolumes)
if (strlen(m_szPassword) > 0)
{
snprintf(szPasswordParam, 1024, "-p%s", m_szPassword);
szPasswordParam[1024-1] = '\0';
szArgs[3] = szPasswordParam;
}
char szUnpackDirParam[1024];
snprintf(szUnpackDirParam, 1024, "-o%s", m_szUnpackDir);
szUnpackDirParam[1024-1] = '\0';
szArgs[4] = szUnpackDirParam;
szArgs[5] = bMultiVolumes ? "*.7z.001" : "*.7z";
@@ -296,179 +272,6 @@ void UnpackController::ExecuteSevenZip(bool bMultiVolumes)
}
}
void UnpackController::JoinSplittedFiles()
{
SetLogPrefix("Join");
SetProgressLabel("");
m_pPostInfo->SetStageProgress(0);
// determine groups
FileList groups;
RegEx regExSplitExt(".*\\.[a-z,0-9]{3}\\.001$");
DirBrowser dir(m_szDestDir);
while (const char* filename = dir.Next())
{
char szFullFilename[1024];
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
szFullFilename[1024-1] = '\0';
if (strcmp(filename, ".") && strcmp(filename, "..") && !Util::DirectoryExists(szFullFilename))
{
if (regExSplitExt.Match(filename) && !FileHasRarSignature(szFullFilename))
{
if (!JoinFile(filename))
{
m_bUnpackOK = false;
break;
}
}
}
}
SetLogPrefix(NULL);
SetProgressLabel("");
}
bool UnpackController::JoinFile(const char* szFragBaseName)
{
char szDestBaseName[1024];
strncpy(szDestBaseName, szFragBaseName, 1024);
szDestBaseName[1024-1] = '\0';
// trim extension
char* szExtension = strrchr(szDestBaseName, '.');
*szExtension = '\0';
char szFullFilename[1024];
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, szFragBaseName);
szFullFilename[1024-1] = '\0';
long long lFirstSegmentSize = Util::FileSize(szFullFilename);
long long lDifSegmentSize = 0;
// Validate joinable file:
// - fragments have continuous numbers (no holes);
// - fragments have the same size (except of the last fragment);
// - the last fragment must be smaller than other fragments,
// if it has the same size it is probably not the last and there are missing fragments.
RegEx regExSplitExt(".*\\.[a-z,0-9]{3}\\.[0-9]{3}$");
int iCount = 0;
int iMin = -1;
int iMax = -1;
int iDifSizeCount = 0;
int iDifSizeMin = 999999;
DirBrowser dir(m_szDestDir);
while (const char* filename = dir.Next())
{
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
szFullFilename[1024-1] = '\0';
if (strcmp(filename, ".") && strcmp(filename, "..") && !Util::DirectoryExists(szFullFilename) &&
regExSplitExt.Match(filename))
{
const char* szSegExt = strrchr(filename, '.');
int iSegNum = atoi(szSegExt + 1);
iCount++;
iMin = iSegNum < iMin || iMin == -1 ? iSegNum : iMin;
iMax = iSegNum > iMax ? iSegNum : iMax;
long long lSegmentSize = Util::FileSize(szFullFilename);
if (lSegmentSize != lFirstSegmentSize)
{
iDifSizeCount++;
iDifSizeMin = iSegNum < iDifSizeMin ? iSegNum : iDifSizeMin;
lDifSegmentSize = lSegmentSize;
}
}
}
int iCorrectedCount = iCount - (iMin == 0 ? 1 : 0);
if ((iMin > 1) || iCorrectedCount != iMax ||
((iDifSizeMin != iCorrectedCount || iDifSizeMin > iMax) &&
m_pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psSuccess))
{
PrintMessage(Message::mkWarning, "Could not join splitted file %s: missing fragments detected", szDestBaseName);
return false;
}
// Now can join
PrintMessage(Message::mkInfo, "Joining splitted file %s", szDestBaseName);
m_pPostInfo->SetStageProgress(0);
char szErrBuf[256];
char szDestFilename[1024];
snprintf(szDestFilename, 1024, "%s%c%s", m_szUnpackDir, PATH_SEPARATOR, szDestBaseName);
szDestFilename[1024-1] = '\0';
FILE* pOutFile = fopen(szDestFilename, FOPEN_WBP);
if (!pOutFile)
{
error("Could not create file %s: %s", szDestFilename, Util::GetLastErrorMessage(szErrBuf, sizeof(szErrBuf)));
return false;
}
if (g_pOptions->GetWriteBuffer() > 0)
{
setvbuf(pOutFile, NULL, _IOFBF, g_pOptions->GetWriteBuffer() * 1024);
}
long long lTotalSize = lFirstSegmentSize * (iCount - 1) + lDifSegmentSize;
long long lWritten = 0;
static const int BUFFER_SIZE = 1024 * 50;
char* buffer = (char*)malloc(BUFFER_SIZE);
bool bOK = true;
for (int i = iMin; i <= iMax; i++)
{
PrintMessage(Message::mkInfo, "Joining from %s.%.3i", szDestBaseName, i);
char szMessage[1024];
snprintf(szMessage, 1024, "Joining from %s.%.3i", szDestBaseName, i);
szMessage[1024-1] = '\0';
SetProgressLabel(szMessage);
char szFragFilename[1024];
snprintf(szFragFilename, 1024, "%s%c%s.%.3i", m_szDestDir, PATH_SEPARATOR, szDestBaseName, i);
szFragFilename[1024-1] = '\0';
if (!Util::FileExists(szFragFilename))
{
break;
}
FILE* pInFile = fopen(szFragFilename, FOPEN_RB);
if (pInFile)
{
int cnt = BUFFER_SIZE;
while (cnt == BUFFER_SIZE)
{
cnt = (int)fread(buffer, 1, BUFFER_SIZE, pInFile);
fwrite(buffer, 1, cnt, pOutFile);
lWritten += cnt;
m_pPostInfo->SetStageProgress(int(lWritten * 1000 / lTotalSize));
}
fclose(pInFile);
char szFragFilename[1024];
snprintf(szFragFilename, 1024, "%s.%.3i", szDestBaseName, i);
szFragFilename[1024-1] = '\0';
m_JoinedFiles.push_back(strdup(szFragFilename));
}
else
{
error("Could not open file %s", szFragFilename);
bOK = false;
break;
}
}
fclose(pOutFile);
free(buffer);
return bOK;
}
void UnpackController::Completed()
{
bool bCleanupSuccess = Cleanup();
@@ -488,14 +291,11 @@ void UnpackController::Completed()
else
{
#ifndef DISABLE_PARCHECK
if (!m_bUnpackOK &&
(m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped ||
!m_pPostInfo->GetNZBInfo()->GetParFull()) &&
!m_bUnpackStartError && !m_bUnpackSpaceError &&
(!m_bUnpackPasswordError5 || m_bUnpackPasswordError4) &&
(!GetTerminated() || m_bAutoTerminated) && m_bHasParFiles)
if (!m_bUnpackOK && m_pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped &&
!m_bUnpackStartError && !m_bUnpackSpaceError && !m_bUnpackPasswordError &&
!GetTerminated() && m_bHasParFiles)
{
RequestParCheck(true);
RequestParCheck();
}
else
#endif
@@ -503,8 +303,7 @@ void UnpackController::Completed()
PrintMessage(Message::mkError, "%s failed", m_szInfoNameUp);
m_pPostInfo->GetNZBInfo()->SetUnpackStatus(
m_bUnpackSpaceError ? NZBInfo::usSpace :
m_bUnpackPasswordError5 || (m_bUnpackPasswordError4 &&
m_pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSuccess) ? NZBInfo::usPassword :
m_bUnpackPasswordError ? NZBInfo::usPassword :
NZBInfo::usFailure);
m_pPostInfo->SetStage(PostInfo::ptQueued);
}
@@ -512,11 +311,10 @@ void UnpackController::Completed()
}
#ifndef DISABLE_PARCHECK
void UnpackController::RequestParCheck(bool bForceRepair)
void UnpackController::RequestParCheck()
{
PrintMessage(Message::mkInfo, "%s requested par-check/repair", m_szInfoNameUp);
m_pPostInfo->SetRequestParCheck(true);
m_pPostInfo->SetForceRepair(bForceRepair);
m_pPostInfo->SetStage(PostInfo::ptFinished);
}
#endif
@@ -552,14 +350,12 @@ void UnpackController::CheckArchiveFiles(bool bScanNonStdFiles)
m_bHasNonStdRarFiles = false;
m_bHasSevenZipFiles = false;
m_bHasSevenZipMultiFiles = false;
m_bHasSplittedFiles = false;
RegEx regExRar(".*\\.rar$");
RegEx regExRarMultiSeq(".*\\.(r|s)[0-9][0-9]$");
RegEx regExSevenZip(".*\\.7z$");
RegEx regExSevenZipMulti(".*\\.7z\\.[0-9]+$");
RegEx regExNumExt(".*\\.[0-9]+$");
RegEx regExSplitExt(".*\\.[a-z,0-9]{3}\\.[0-9]{3}$");
DirBrowser dir(m_szDestDir);
while (const char* filename = dir.Next())
@@ -570,9 +366,6 @@ void UnpackController::CheckArchiveFiles(bool bScanNonStdFiles)
if (strcmp(filename, ".") && strcmp(filename, "..") && !Util::DirectoryExists(szFullFilename))
{
const char* szExt = strchr(filename, '.');
int iExtNum = szExt ? atoi(szExt + 1) : -1;
if (regExRar.Match(filename))
{
m_bHasRarFiles = true;
@@ -585,16 +378,12 @@ void UnpackController::CheckArchiveFiles(bool bScanNonStdFiles)
{
m_bHasSevenZipMultiFiles = true;
}
else if (bScanNonStdFiles && !m_bHasNonStdRarFiles && iExtNum > 1 &&
else if (bScanNonStdFiles && !m_bHasNonStdRarFiles &&
!regExRarMultiSeq.Match(filename) && regExNumExt.Match(filename) &&
FileHasRarSignature(szFullFilename))
{
m_bHasNonStdRarFiles = true;
}
else if (regExSplitExt.Match(filename) && (iExtNum == 0 || iExtNum == 1))
{
m_bHasSplittedFiles = true;
}
}
}
}
@@ -684,7 +473,6 @@ bool UnpackController::Cleanup()
RegEx regExRarMultiSeq(".*\\.[r-z][0-9][0-9]$");
RegEx regExSevenZip(".*\\.7z$|.*\\.7z\\.[0-9]+$");
RegEx regExNumExt(".*\\.[0-9]+$");
RegEx regExSplitExt(".*\\.[a-z,0-9]{3}\\.[0-9]{3}$");
DirBrowser dir(m_szDestDir);
while (const char* filename = dir.Next())
@@ -697,9 +485,8 @@ bool UnpackController::Cleanup()
!Util::DirectoryExists(szFullFilename) &&
(m_bInterDir || !extractedFiles.Exists(filename)) &&
(regExRar.Match(filename) || regExSevenZip.Match(filename) ||
(regExRarMultiSeq.Match(filename) && FileHasRarSignature(szFullFilename)) ||
(m_bHasNonStdRarFiles && regExNumExt.Match(filename) && FileHasRarSignature(szFullFilename)) ||
(m_bHasSplittedFiles && regExSplitExt.Match(filename) && m_JoinedFiles.Exists(filename))))
(regExRarMultiSeq.Match(filename) && FileHasRarSignature(szFullFilename)) ||
(m_bHasNonStdRarFiles && regExNumExt.Match(filename) && FileHasRarSignature(szFullFilename))))
{
PrintMessage(Message::mkInfo, "Deleting file %s", filename);
@@ -820,35 +607,6 @@ void UnpackController::AddMessage(Message::EKind eKind, const char* szText)
SetProgressLabel(szText + 7);
}
if (m_eUnpacker == upUnrar &&
(!strncmp(szText, "Unrar: Checksum error in the encrypted file", 42) ||
!strncmp(szText, "Unrar: CRC failed in the encrypted file", 39)))
{
m_bUnpackPasswordError4 = true;
}
if (m_eUnpacker == upUnrar && !strncmp(szText, "Unrar: The specified password is incorrect.'", 43))
{
m_bUnpackPasswordError5 = true;
}
int iLen = strlen(szText);
if (m_eUnpacker == upUnrar && !IsStopped() && (m_bUnpackPasswordError4 || m_bUnpackPasswordError5 ||
strstr(szText, " : packed data CRC failed in volume") ||
strstr(szText, " : packed data checksum error in volume") ||
(iLen > 13 && !strncmp(szText + iLen - 13, " - CRC failed", 13)) ||
(iLen > 18 && !strncmp(szText + iLen - 18, " - checksum failed", 18)) ||
!strncmp(szText, "Unrar: WARNING: You need to start extraction from a previous volume", 67)))
{
char szMsgText[1024];
snprintf(szMsgText, 1024, "Cancelling %s due to errors", m_szInfoName);
szMsgText[1024-1] = '\0';
ScriptController::AddMessage(Message::mkWarning, szMsgText);
m_pPostInfo->AppendMessage(Message::mkWarning, szMsgText);
m_bAutoTerminated = true;
Stop();
}
if ((m_eUnpacker == upUnrar && !strncmp(szText, "Unrar: All OK", 13)) ||
(m_eUnpacker == upSevenZip && !strncmp(szText, "7-Zip: Everything is Ok", 23)))
{

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2013 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,32 +67,26 @@ private:
bool m_bHasNonStdRarFiles;
bool m_bHasSevenZipFiles;
bool m_bHasSevenZipMultiFiles;
bool m_bHasSplittedFiles;
bool m_bUnpackOK;
bool m_bUnpackStartError;
bool m_bUnpackSpaceError;
bool m_bUnpackPasswordError4;
bool m_bUnpackPasswordError5;
bool m_bUnpackPasswordError;
bool m_bCleanedUpDisk;
bool m_bAutoTerminated;
EUnpacker m_eUnpacker;
bool m_bFinalDirCreated;
FileList m_JoinedFiles;
protected:
virtual bool ReadLine(char* szBuf, int iBufSize, FILE* pStream);
virtual void AddMessage(Message::EKind eKind, const char* szText);
void ExecuteUnrar();
void ExecuteSevenZip(bool bMultiVolumes);
void JoinSplittedFiles();
bool JoinFile(const char* szFragBaseName);
void Completed();
void CreateUnpackDir();
bool Cleanup();
void CheckArchiveFiles(bool bScanNonStdFiles);
void SetProgressLabel(const char* szProgressLabel);
#ifndef DISABLE_PARCHECK
void RequestParCheck(bool bForceRepair);
void RequestParCheck();
#endif
bool FileHasRarSignature(const char* szFilename);

View File

@@ -136,7 +136,7 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue)
return false;
}
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 51);
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 47);
// save nzb-infos
SaveNZBQueue(pDownloadQueue, outfile);
@@ -179,7 +179,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue, Servers* pServe
char FileSignatur[128];
fgets(FileSignatur, sizeof(FileSignatur), infile);
iFormatVersion = ParseFormatVersion(FileSignatur);
if (iFormatVersion < 3 || iFormatVersion > 51)
if (iFormatVersion < 3 || iFormatVersion > 47)
{
error("Could not load diskstate due to file version mismatch");
fclose(infile);
@@ -363,9 +363,6 @@ void DiskState::SaveNZBInfo(NZBInfo* pNZBInfo, FILE* outfile)
(int)pNZBInfo->GetAddUrlPaused());
fprintf(outfile, "%i,%i\n", pNZBInfo->GetFileCount(), pNZBInfo->GetParkedFileCount());
fprintf(outfile, "%i,%i\n", (int)pNZBInfo->GetMinTime(), (int)pNZBInfo->GetMaxTime());
fprintf(outfile, "%i,%i,%i\n", (int)pNZBInfo->GetParFull(),
pNZBInfo->GetPostInfo() ? (int)pNZBInfo->GetPostInfo()->GetForceParFull() : 0,
pNZBInfo->GetPostInfo() ? (int)pNZBInfo->GetPostInfo()->GetForceRepair() : 0);
fprintf(outfile, "%u,%u\n", pNZBInfo->GetFullContentHash(), pNZBInfo->GetFilteredContentHash());
@@ -385,19 +382,23 @@ void DiskState::SaveNZBInfo(NZBInfo* pNZBInfo, FILE* outfile)
fprintf(outfile, "%s\n", pNZBInfo->GetDupeKey());
fprintf(outfile, "%i,%i\n", (int)pNZBInfo->GetDupeMode(), pNZBInfo->GetDupeScore());
Util::SplitInt64(pNZBInfo->GetDownloadedSize(), &High1, &Low1);
fprintf(outfile, "%lu,%lu,%i,%i,%i,%i,%i\n", High1, Low1, pNZBInfo->GetDownloadSec(), pNZBInfo->GetPostTotalSec(),
pNZBInfo->GetParSec(), pNZBInfo->GetRepairSec(), pNZBInfo->GetUnpackSec());
char DestDirSlash[1024];
snprintf(DestDirSlash, 1023, "%s%c", pNZBInfo->GetDestDir(), PATH_SEPARATOR);
int iDestDirLen = strlen(DestDirSlash);
fprintf(outfile, "%i\n", (int)pNZBInfo->GetCompletedFiles()->size());
for (CompletedFiles::iterator it = pNZBInfo->GetCompletedFiles()->begin(); it != pNZBInfo->GetCompletedFiles()->end(); it++)
for (NZBInfo::Files::iterator it = pNZBInfo->GetCompletedFiles()->begin(); it != pNZBInfo->GetCompletedFiles()->end(); it++)
{
CompletedFile* pCompletedFile = *it;
fprintf(outfile, "%i,%i,%lu,%s\n", pCompletedFile->GetID(), (int)pCompletedFile->GetStatus(),
pCompletedFile->GetCrc(), pCompletedFile->GetFileName());
char* szFilename = *it;
// do not save full path to reduce the size of queue-file
if (!strncmp(DestDirSlash, szFilename, iDestDirLen))
{
fprintf(outfile, "%s\n", szFilename + iDestDirLen);
}
else
{
fprintf(outfile, "%s\n", szFilename);
}
}
fprintf(outfile, "%i\n", (int)pNZBInfo->GetParameters()->size());
@@ -671,18 +672,6 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile,
pNZBInfo->SetMaxTime((time_t)iMaxTime);
}
if (iFormatVersion >= 51)
{
int iParFull, iForceParFull, iForceRepair;
if (fscanf(infile, "%i,%i,%i\n", &iParFull, &iForceParFull, &iForceRepair) != 3) goto error;
pNZBInfo->SetParFull((bool)iParFull);
if (pNZBInfo->GetPostInfo())
{
pNZBInfo->GetPostInfo()->SetForceParFull((bool)iForceParFull);
pNZBInfo->GetPostInfo()->SetForceRepair((bool)iForceRepair);
}
}
if (true) // clang requires a block for goto to work
{
unsigned int iFullContentHash = 0, iFilteredContentHash = 0;
@@ -757,18 +746,6 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile,
pNZBInfo->SetDupeScore(iDupeScore);
}
if (iFormatVersion >= 48)
{
unsigned long High1, Low1, iDownloadSec, iPostTotalSec, iParSec, iRepairSec, iUnpackSec;
if (fscanf(infile, "%lu,%lu,%i,%i,%i,%i,%i\n", &High1, &Low1, &iDownloadSec, &iPostTotalSec, &iParSec, &iRepairSec, &iUnpackSec) != 7) goto error;
pNZBInfo->SetDownloadedSize(Util::JoinInt64(High1, Low1));
pNZBInfo->SetDownloadSec(iDownloadSec);
pNZBInfo->SetPostTotalSec(iPostTotalSec);
pNZBInfo->SetParSec(iParSec);
pNZBInfo->SetRepairSec(iRepairSec);
pNZBInfo->SetUnpackSec(iUnpackSec);
}
if (iFormatVersion >= 4)
{
int iFileCount;
@@ -778,32 +755,16 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile,
if (!fgets(buf, sizeof(buf), infile)) goto error;
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
int iID = 0;
// restore full file name.
char* szFileName = buf;
int iStatus = 0;
unsigned long lCrc = 0;
if (iFormatVersion >= 49)
char FullFileName[1024];
if (!strchr(buf, PATH_SEPARATOR))
{
if (iFormatVersion >= 50)
{
if (sscanf(buf, "%i,%i,%lu", &iID, &iStatus, &lCrc) != 3) goto error;
szFileName = strchr(buf, ',');
if (szFileName) szFileName = strchr(szFileName+1, ',');
if (szFileName) szFileName = strchr(szFileName+1, ',');
}
else
{
if (sscanf(buf, "%i,%lu", &iStatus, &lCrc) != 2) goto error;
szFileName = strchr(buf + 2, ',');
}
if (szFileName)
{
szFileName++;
}
snprintf(FullFileName, 1023, "%s%c%s", pNZBInfo->GetDestDir(), PATH_SEPARATOR, buf);
szFileName = FullFileName;
}
pNZBInfo->GetCompletedFiles()->push_back(new CompletedFile(iID, szFileName, (CompletedFile::EStatus)iStatus, lCrc));
pNZBInfo->GetCompletedFiles()->push_back(strdup(szFileName));
}
}
@@ -864,8 +825,7 @@ bool DiskState::LoadNZBInfo(NZBInfo* pNZBInfo, Servers* pServers, FILE* infile,
int iKind, iTime;
sscanf(buf, "%i,%i", &iKind, &iTime);
char* szText = strchr(buf + 2, ',');
if (szText)
{
if (szText) {
szText++;
}
pNZBInfo->AppendMessage((Message::EKind)iKind, (time_t)iTime, szText);
@@ -1018,16 +978,13 @@ bool DiskState::LoadServerStats(ServerStatList* pServerStatList, Servers* pServe
int iServerID, iSuccessArticles, iFailedArticles;
if (fscanf(infile, "%i,%i,%i\n", &iServerID, &iSuccessArticles, &iFailedArticles) != 3) goto error;
if (pServers)
// find server (id could change if config file was edited)
for (Servers::iterator it = pServers->begin(); it != pServers->end(); it++)
{
// find server (id could change if config file was edited)
for (Servers::iterator it = pServers->begin(); it != pServers->end(); it++)
NewsServer* pNewsServer = *it;
if (pNewsServer->GetStateID() == iServerID)
{
NewsServer* pNewsServer = *it;
if (pNewsServer->GetStateID() == iServerID)
{
pServerStatList->StatOp(pNewsServer->GetID(), iSuccessArticles, iFailedArticles, ServerStatList::soSet);
}
pServerStatList->StatOp(pNewsServer->GetID(), iSuccessArticles, iFailedArticles, ServerStatList::soSet);
}
}
}
@@ -1216,12 +1173,12 @@ error:
return false;
}
bool DiskState::SaveFileState(FileInfo* pFileInfo, bool bCompleted)
bool DiskState::SaveFileState(FileInfo* pFileInfo)
{
debug("Saving FileState to disk");
char szFilename[1024];
snprintf(szFilename, 1024, "%s%i%s", g_pOptions->GetQueueDir(), pFileInfo->GetID(), bCompleted ? "c" : "s");
snprintf(szFilename, 1024, "%s%is", g_pOptions->GetQueueDir(), pFileInfo->GetID());
szFilename[1024-1] = '\0';
FILE* outfile = fopen(szFilename, FOPEN_WB);
@@ -1232,7 +1189,7 @@ bool DiskState::SaveFileState(FileInfo* pFileInfo, bool bCompleted)
return false;
}
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 2);
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 1);
fprintf(outfile, "%i,%i\n", pFileInfo->GetSuccessArticles(), pFileInfo->GetFailedArticles());
@@ -1248,22 +1205,19 @@ bool DiskState::SaveFileState(FileInfo* pFileInfo, bool bCompleted)
for (FileInfo::Articles::iterator it = pFileInfo->GetArticles()->begin(); it != pFileInfo->GetArticles()->end(); it++)
{
ArticleInfo* pArticleInfo = *it;
fprintf(outfile, "%i,%lu,%i,%lu\n", (int)pArticleInfo->GetStatus(), (unsigned long)pArticleInfo->GetSegmentOffset(),
pArticleInfo->GetSegmentSize(), (unsigned long)pArticleInfo->GetCrc());
fprintf(outfile, "%i\n", (int)pArticleInfo->GetStatus());
}
fclose(outfile);
return true;
}
bool DiskState::LoadFileState(FileInfo* pFileInfo, Servers* pServers, bool bCompleted)
bool DiskState::LoadFileState(FileInfo* pFileInfo, Servers* pServers)
{
char szFilename[1024];
snprintf(szFilename, 1024, "%s%i%s", g_pOptions->GetQueueDir(), pFileInfo->GetID(), bCompleted ? "c" : "s");
snprintf(szFilename, 1024, "%s%is", g_pOptions->GetQueueDir(), pFileInfo->GetID());
szFilename[1024-1] = '\0';
bool bHasArticles = !pFileInfo->GetArticles()->empty();
FILE* infile = fopen(szFilename, FOPEN_RB);
if (!infile)
@@ -1279,7 +1233,7 @@ bool DiskState::LoadFileState(FileInfo* pFileInfo, Servers* pServers, bool bComp
{
if (buf[0] != 0) buf[strlen(buf)-1] = 0; // remove traling '\n'
iFormatVersion = ParseFormatVersion(buf);
if (iFormatVersion > 2)
if (iFormatVersion > 1)
{
error("Could not load diskstate due to file version mismatch");
goto error;
@@ -1310,28 +1264,8 @@ bool DiskState::LoadFileState(FileInfo* pFileInfo, Servers* pServers, bool bComp
if (fscanf(infile, "%i\n", &size) != 1) goto error;
for (int i = 0; i < size; i++)
{
if (!bHasArticles)
{
pFileInfo->GetArticles()->push_back(new ArticleInfo());
}
ArticleInfo* pa = pFileInfo->GetArticles()->at(i);
int iStatus;
if (iFormatVersion >= 2)
{
unsigned long iSegmentOffset, iCrc;
int iSegmentSize;
if (fscanf(infile, "%i,%lu,%i,%lu\n", &iStatus, &iSegmentOffset, &iSegmentSize, &iCrc) != 4) goto error;
pa->SetSegmentOffset(iSegmentOffset);
pa->SetSegmentSize(iSegmentSize);
pa->SetCrc(iCrc);
}
else
{
if (fscanf(infile, "%i\n", &iStatus) != 1) goto error;
}
if (fscanf(infile, "%i\n", &iStatus) != 1) goto error;
ArticleInfo::EStatus eStatus = (ArticleInfo::EStatus)iStatus;
if (eStatus == ArticleInfo::aiRunning)
@@ -1341,7 +1275,7 @@ bool DiskState::LoadFileState(FileInfo* pFileInfo, Servers* pServers, bool bComp
// don't allow all articles be completed or the file will stuck.
// such states should never be saved on disk but just in case.
if (iCompletedArticles == size - 1 && !bCompleted)
if (iCompletedArticles == size - 1)
{
eStatus = ArticleInfo::aiUndefined;
}
@@ -1350,7 +1284,7 @@ bool DiskState::LoadFileState(FileInfo* pFileInfo, Servers* pServers, bool bComp
iCompletedArticles++;
}
pa->SetStatus(eStatus);
pFileInfo->GetArticles()->at(i)->SetStatus(eStatus);
}
pFileInfo->SetCompletedArticles(iCompletedArticles);
@@ -1364,35 +1298,6 @@ error:
return false;
}
void DiskState::DiscardFiles(NZBInfo* pNZBInfo)
{
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
{
FileInfo* pFileInfo = *it;
DiscardFile(pFileInfo, true, true, true);
}
for (CompletedFiles::iterator it = pNZBInfo->GetCompletedFiles()->begin(); it != pNZBInfo->GetCompletedFiles()->end(); it++)
{
CompletedFile* pCompletedFile = *it;
if (pCompletedFile->GetStatus() != CompletedFile::cfSuccess && pCompletedFile->GetID() > 0)
{
char szFilename[1024];
snprintf(szFilename, 1024, "%s%i", g_pOptions->GetQueueDir(), pCompletedFile->GetID());
szFilename[1024-1] = '\0';
remove(szFilename);
snprintf(szFilename, 1024, "%s%is", g_pOptions->GetQueueDir(), pCompletedFile->GetID());
szFilename[1024-1] = '\0';
remove(szFilename);
snprintf(szFilename, 1024, "%s%ic", g_pOptions->GetQueueDir(), pCompletedFile->GetID());
szFilename[1024-1] = '\0';
remove(szFilename);
}
}
}
bool DiskState::LoadPostQueue12(DownloadQueue* pDownloadQueue, NZBList* pNZBList, FILE* infile, int iFormatVersion)
{
debug("Loading post-queue from disk");
@@ -1833,7 +1738,6 @@ bool DiskState::LoadHistory(DownloadQueue* pDownloadQueue, NZBList* pNZBList, Se
{
pNZBInfo = new NZBInfo();
if (!LoadNZBInfo(pNZBInfo, pServers, infile, iFormatVersion)) goto error;
pNZBInfo->LeavePostProcess();
}
pHistoryInfo = new HistoryInfo(pNZBInfo);
@@ -1949,16 +1853,6 @@ void DiskState::DiscardDownloadQueue()
snprintf(szFullFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), filename);
szFullFilename[1024-1] = '\0';
remove(szFullFilename);
// delete file state file
snprintf(szFullFilename, 1024, "%s%ss", g_pOptions->GetQueueDir(), filename);
szFullFilename[1024-1] = '\0';
remove(szFullFilename);
// delete failed info file
snprintf(szFullFilename, 1024, "%s%sc", g_pOptions->GetQueueDir(), filename);
szFullFilename[1024-1] = '\0';
remove(szFullFilename);
}
}
}
@@ -1973,33 +1867,20 @@ bool DiskState::DownloadQueueExists()
return Util::FileExists(fileName);
}
bool DiskState::DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeletePartialState, bool bDeleteCompletedState)
bool DiskState::DiscardFile(FileInfo* pFileInfo)
{
char fileName[1024];
// delete diskstate-file for file-info
// info and articles file
if (bDeleteData)
{
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), pFileInfo->GetID());
fileName[1024-1] = '\0';
remove(fileName);
}
char fileName[1024];
snprintf(fileName, 1024, "%s%i", g_pOptions->GetQueueDir(), pFileInfo->GetID());
fileName[1024-1] = '\0';
remove(fileName);
// partial state file
if (bDeletePartialState)
{
snprintf(fileName, 1024, "%s%is", g_pOptions->GetQueueDir(), pFileInfo->GetID());
fileName[1024-1] = '\0';
remove(fileName);
}
// completed state file
if (bDeleteCompletedState)
{
snprintf(fileName, 1024, "%s%ic", g_pOptions->GetQueueDir(), pFileInfo->GetID());
fileName[1024-1] = '\0';
remove(fileName);
}
// state file
snprintf(fileName, 1024, "%s%is", g_pOptions->GetQueueDir(), pFileInfo->GetID());
fileName[1024-1] = '\0';
remove(fileName);
return true;
}
@@ -2341,12 +2222,6 @@ void DiskState::CalcNZBFileStats(NZBInfo* pNZBInfo, int iFormatVersion)
bool DiskState::LoadAllFileStates(DownloadQueue* pDownloadQueue, Servers* pServers)
{
char szCacheFlagFilename[1024];
snprintf(szCacheFlagFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), "acache");
szCacheFlagFilename[1024-1] = '\0';
bool bCacheWasActive = Util::FileExists(szCacheFlagFilename);
DirBrowser dir(g_pOptions->GetQueueDir());
while (const char* filename = dir.Next())
{
@@ -2354,7 +2229,7 @@ bool DiskState::LoadAllFileStates(DownloadQueue* pDownloadQueue, Servers* pServe
char suffix;
if (sscanf(filename, "%i%c", &id, &suffix) == 2 && suffix == 's')
{
if (g_pOptions->GetContinuePartial() && !bCacheWasActive)
if (g_pOptions->GetContinuePartial())
{
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
@@ -2365,7 +2240,7 @@ bool DiskState::LoadAllFileStates(DownloadQueue* pDownloadQueue, Servers* pServe
if (pFileInfo->GetID() == id)
{
if (!LoadArticles(pFileInfo)) goto error;
if (!LoadFileState(pFileInfo, pServers, false)) goto error;
if (!LoadFileState(pFileInfo, pServers)) goto error;
}
}
}
@@ -2859,28 +2734,3 @@ error:
return false;
}
void DiskState::WriteCacheFlag()
{
char szFlagFilename[1024];
snprintf(szFlagFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), "acache");
szFlagFilename[1024-1] = '\0';
FILE* outfile = fopen(szFlagFilename, FOPEN_WB);
if (!outfile)
{
error("Error saving diskstate: Could not create file %s", szFlagFilename);
return;
}
fclose(outfile);
}
void DiskState::DeleteCacheFlag()
{
char szFlagFilename[1024];
snprintf(szFlagFilename, 1024, "%s%s", g_pOptions->GetQueueDir(), "acache");
szFlagFilename[1024-1] = '\0';
remove(szFlagFilename);
}

View File

@@ -58,6 +58,7 @@ private:
bool LoadVolumeStat(Servers* pServers, ServerVolumes* pServerVolumes, FILE* infile, int iFormatVersion);
void CalcFileStats(DownloadQueue* pDownloadQueue, int iFormatVersion);
void CalcNZBFileStats(NZBInfo* pNZBInfo, int iFormatVersion);
bool LoadFileState(FileInfo* pFileInfo, Servers* pServers);
bool LoadAllFileStates(DownloadQueue* pDownloadQueue, Servers* pServers);
void SaveServerStats(ServerStatList* pServerStatList, FILE* outfile);
bool LoadServerStats(ServerStatList* pServerStatList, Servers* pServers, FILE* infile);
@@ -79,19 +80,15 @@ public:
bool SaveDownloadQueue(DownloadQueue* pDownloadQueue);
bool LoadDownloadQueue(DownloadQueue* pDownloadQueue, Servers* pServers);
bool SaveFile(FileInfo* pFileInfo);
bool SaveFileState(FileInfo* pFileInfo, bool bCompleted);
bool LoadFileState(FileInfo* pFileInfo, Servers* pServers, bool bCompleted);
bool SaveFileState(FileInfo* pFileInfo);
bool LoadArticles(FileInfo* pFileInfo);
void DiscardDownloadQueue();
bool DiscardFile(FileInfo* pFileInfo, bool bDeleteData, bool bDeletePartialState, bool bDeleteCompletedState);
void DiscardFiles(NZBInfo* pNZBInfo);
bool DiscardFile(FileInfo* pFileInfo);
bool SaveFeeds(Feeds* pFeeds, FeedHistory* pFeedHistory);
bool LoadFeeds(Feeds* pFeeds, FeedHistory* pFeedHistory);
bool SaveStats(Servers* pServers, ServerVolumes* pServerVolumes);
bool LoadStats(Servers* pServers, ServerVolumes* pServerVolumes, bool* pPerfectMatch);
void CleanupTempDir(DownloadQueue* pDownloadQueue);
void WriteCacheFlag();
void DeleteCacheFlag();
};
#endif

View File

@@ -41,12 +41,10 @@
#include "nzbget.h"
#include "DownloadInfo.h"
#include "ArticleWriter.h"
#include "Options.h"
#include "Util.h"
extern Options* g_pOptions;
extern ArticleCache* g_pArticleCache;
int FileInfo::m_iIDGen = 0;
int FileInfo::m_iIDMax = 0;
@@ -332,16 +330,6 @@ NZBInfo::NZBInfo() : m_FileList(true)
m_pPostInfo = NULL;
m_iIDMessageGen = 0;
m_iID = ++m_iIDGen;
m_lDownloadedSize = 0;
m_iDownloadSec = 0;
m_iPostTotalSec = 0;
m_iParSec = 0;
m_iRepairSec = 0;
m_iUnpackSec = 0;
m_tDownloadStartTime = 0;
m_bReprocess = false;
m_tQueueScriptTime = 0;
m_bParFull = false;
}
NZBInfo::~NZBInfo()
@@ -398,9 +386,9 @@ int NZBInfo::GenerateID()
void NZBInfo::ClearCompletedFiles()
{
for (CompletedFiles::iterator it = m_completedFiles.begin(); it != m_completedFiles.end(); it++)
for (Files::iterator it = m_completedFiles.begin(); it != m_completedFiles.end(); it++)
{
delete *it;
free(*it);
}
m_completedFiles.clear();
}
@@ -737,25 +725,6 @@ void NZBInfo::LeavePostProcess()
m_pPostInfo = NULL;
}
void NZBInfo::SetActiveDownloads(int iActiveDownloads)
{
if (((m_iActiveDownloads == 0 && iActiveDownloads > 0) ||
(m_iActiveDownloads > 0 && iActiveDownloads == 0)) &&
m_eKind == NZBInfo::nkNzb)
{
if (iActiveDownloads > 0)
{
m_tDownloadStartTime = time(NULL);
}
else
{
m_iDownloadSec += time(NULL) - m_tDownloadStartTime;
m_tDownloadStartTime = 0;
}
}
m_iActiveDownloads = iActiveDownloads;
}
bool NZBInfo::IsDupeSuccess()
{
bool bFailure =
@@ -800,10 +769,6 @@ const char* NZBInfo::MakeTextStatus(bool bIgnoreScriptStatus)
{
szStatus = "DELETED/DUPE";
}
else if (m_eDeleteStatus == NZBInfo::dsBad)
{
szStatus = "FAILURE/BAD";
}
else if (m_eParStatus == NZBInfo::psFailure)
{
szStatus = "FAILURE/PAR";
@@ -930,38 +895,20 @@ void NZBList::Remove(NZBInfo* pNZBInfo)
}
}
NZBInfo* NZBList::Find(int iID)
{
for (iterator it = begin(); it != end(); it++)
{
NZBInfo* pNZBInfo = *it;
if (pNZBInfo->GetID() == iID)
{
return pNZBInfo;
}
}
return NULL;
}
ArticleInfo::ArticleInfo()
{
//debug("Creating ArticleInfo");
m_szMessageID = NULL;
m_iSize = 0;
m_pSegmentContent = NULL;
m_iSegmentOffset = 0;
m_iSegmentSize = 0;
m_eStatus = aiUndefined;
m_szResultFilename = NULL;
m_lCrc = 0;
m_szMessageID = NULL;
m_iSize = 0;
m_eStatus = aiUndefined;
m_szResultFilename = NULL;
}
ArticleInfo::~ ArticleInfo()
{
//debug("Destroying ArticleInfo");
DiscardSegment();
free(m_szMessageID);
free(m_szResultFilename);
}
@@ -978,26 +925,8 @@ void ArticleInfo::SetResultFilename(const char * v)
m_szResultFilename = strdup(v);
}
void ArticleInfo::AttachSegment(char* pContent, long long iOffset, int iSize)
{
DiscardSegment();
m_pSegmentContent = pContent;
m_iSegmentOffset = iOffset;
m_iSegmentSize = iSize;
}
void ArticleInfo::DiscardSegment()
{
if (m_pSegmentContent)
{
free(m_pSegmentContent);
m_pSegmentContent = NULL;
g_pArticleCache->Free(m_iSegmentSize);
}
}
FileInfo::FileInfo(int iID)
FileInfo::FileInfo()
{
debug("Creating FileInfo");
@@ -1027,9 +956,7 @@ FileInfo::FileInfo(int iID)
m_bExtraPriority = false;
m_iActiveDownloads = 0;
m_bAutoDeleted = false;
m_iCachedArticles = 0;
m_bPartialChanged = false;
m_iID = iID ? iID : ++m_iIDGen;
m_iID = ++m_iIDGen;
}
FileInfo::~ FileInfo()
@@ -1161,30 +1088,6 @@ void FileList::Remove(FileInfo* pFileInfo)
erase(std::find(begin(), end(), pFileInfo));
}
CompletedFile::CompletedFile(int iID, const char* szFileName, EStatus eStatus, unsigned long lCrc)
{
m_iID = iID;
if (FileInfo::m_iIDMax < m_iID)
{
FileInfo::m_iIDMax = m_iID;
}
m_szFileName = strdup(szFileName);
m_eStatus = eStatus;
m_lCrc = lCrc;
}
void CompletedFile::SetFileName(const char* szFileName)
{
free(m_szFileName);
m_szFileName = strdup(szFileName);
}
CompletedFile::~CompletedFile()
{
free(m_szFileName);
}
PostInfo::PostInfo()
{
@@ -1194,8 +1097,6 @@ PostInfo::PostInfo()
m_bWorking = false;
m_bDeleted = false;
m_bRequestParCheck = false;
m_bForceParFull = false;
m_bForceRepair = false;
m_szProgressLabel = strdup("");
m_iFileProgress = 0;
m_iStageProgress = 0;

View File

@@ -89,12 +89,8 @@ private:
int m_iPartNumber;
char* m_szMessageID;
int m_iSize;
char* m_pSegmentContent;
long long m_iSegmentOffset;
int m_iSegmentSize;
EStatus m_eStatus;
char* m_szResultFilename;
unsigned long m_lCrc;
public:
ArticleInfo();
@@ -103,21 +99,12 @@ public:
int GetPartNumber() { return m_iPartNumber; }
const char* GetMessageID() { return m_szMessageID; }
void SetMessageID(const char* szMessageID);
void SetSize(int iSize) { m_iSize = iSize; }
void SetSize(int s) { m_iSize = s; }
int GetSize() { return m_iSize; }
void AttachSegment(char* pContent, long long iOffset, int iSize);
void DiscardSegment();
const char* GetSegmentContent() { return m_pSegmentContent; }
void SetSegmentOffset(long long iSegmentOffset) { m_iSegmentOffset = iSegmentOffset; }
long long GetSegmentOffset() { return m_iSegmentOffset; }
void SetSegmentSize(int iSegmentSize) { m_iSegmentSize = iSegmentSize; }
int GetSegmentSize() { return m_iSegmentSize; }
EStatus GetStatus() { return m_eStatus; }
void SetStatus(EStatus Status) { m_eStatus = Status; }
const char* GetResultFilename() { return m_szResultFilename; }
void SetResultFilename(const char* v);
unsigned long GetCrc() { return m_lCrc; }
void SetCrc(unsigned long lCrc) { m_lCrc = lCrc; }
};
class FileInfo
@@ -155,16 +142,12 @@ private:
bool m_bExtraPriority;
int m_iActiveDownloads;
bool m_bAutoDeleted;
int m_iCachedArticles;
bool m_bPartialChanged;
static int m_iIDGen;
static int m_iIDMax;
friend class CompletedFile;
public:
FileInfo(int iID = 0);
FileInfo();
~FileInfo();
int GetID() { return m_iID; }
void SetID(int iID);
@@ -216,15 +199,11 @@ public:
bool GetOutputInitialized() { return m_bOutputInitialized; }
void SetOutputInitialized(bool bOutputInitialized) { m_bOutputInitialized = bOutputInitialized; }
bool GetExtraPriority() { return m_bExtraPriority; }
void SetExtraPriority(bool bExtraPriority) { m_bExtraPriority = bExtraPriority; }
void SetExtraPriority(bool bExtraPriority) { m_bExtraPriority = bExtraPriority; };
int GetActiveDownloads() { return m_iActiveDownloads; }
void SetActiveDownloads(int iActiveDownloads);
bool GetAutoDeleted() { return m_bAutoDeleted; }
void SetAutoDeleted(bool bAutoDeleted) { m_bAutoDeleted = bAutoDeleted; }
int GetCachedArticles() { return m_iCachedArticles; }
void SetCachedArticles(int iCachedArticles) { m_iCachedArticles = iCachedArticles; }
bool GetPartialChanged() { return m_bPartialChanged; }
void SetPartialChanged(bool bPartialChanged) { m_bPartialChanged = bPartialChanged; }
ServerStatList* GetServerStats() { return &m_ServerStats; }
};
@@ -241,34 +220,6 @@ public:
void Remove(FileInfo* pFileInfo);
};
class CompletedFile
{
public:
enum EStatus
{
cfUnknown,
cfSuccess,
cfPartial,
cfFailure
};
private:
int m_iID;
char* m_szFileName;
EStatus m_eStatus;
unsigned long m_lCrc;
public:
CompletedFile(int iID, const char* szFileName, EStatus eStatus, unsigned long lCrc);
~CompletedFile();
int GetID() { return m_iID; }
void SetFileName(const char* szFileName);
const char* GetFileName() { return m_szFileName; }
EStatus GetStatus() { return m_eStatus; }
unsigned long GetCrc() { return m_lCrc; }
};
typedef std::deque<CompletedFile*> CompletedFiles;
class NZBParameter
{
@@ -312,7 +263,7 @@ public:
private:
char* m_szName;
EStatus m_eStatus;
friend class ScriptStatusList;
public:
@@ -390,8 +341,7 @@ public:
dsNone,
dsManual,
dsHealth,
dsDupe,
dsBad
dsDupe
};
enum EMarkStatus
@@ -418,6 +368,7 @@ public:
nkUrl
};
typedef std::vector<char*> Files;
typedef std::deque<Message*> Messages;
static const int FORCE_PRIORITY = 900;
@@ -458,7 +409,7 @@ private:
time_t m_tMinTime;
time_t m_tMaxTime;
int m_iPriority;
CompletedFiles m_completedFiles;
Files m_completedFiles;
ERenameStatus m_eRenameStatus;
EParStatus m_eParStatus;
EUnpackStatus m_eUnpackStatus;
@@ -492,16 +443,6 @@ private:
Messages m_Messages;
int m_iIDMessageGen;
PostInfo* m_pPostInfo;
long long m_lDownloadedSize;
time_t m_tDownloadStartTime;
int m_iDownloadSec;
int m_iPostTotalSec;
int m_iParSec;
int m_iRepairSec;
int m_iUnpackSec;
bool m_bReprocess;
time_t m_tQueueScriptTime;
bool m_bParFull;
static int m_iIDGen;
static int m_iIDMax;
@@ -544,7 +485,7 @@ public:
int GetRemainingParCount() { return m_iRemainingParCount; }
void SetRemainingParCount(int iRemainingParCount) { m_iRemainingParCount = iRemainingParCount; }
int GetActiveDownloads() { return m_iActiveDownloads; }
void SetActiveDownloads(int iActiveDownloads);
void SetActiveDownloads(int iActiveDownloads) { m_iActiveDownloads = iActiveDownloads; }
long long GetSuccessSize() { return m_lSuccessSize; }
void SetSuccessSize(long long lSuccessSize) { m_lSuccessSize = lSuccessSize; }
long long GetFailedSize() { return m_lFailedSize; }
@@ -582,7 +523,7 @@ public:
void SetMaxTime(time_t tMaxTime) { m_tMaxTime = tMaxTime; }
void BuildDestDirName();
void BuildFinalDirName(char* szFinalDirBuf, int iBufSize);
CompletedFiles* GetCompletedFiles() { return &m_completedFiles; } // needs locking (for shared objects)
Files* GetCompletedFiles() { return &m_completedFiles; } // needs locking (for shared objects)
void ClearCompletedFiles();
ERenameStatus GetRenameStatus() { return m_eRenameStatus; }
void SetRenameStatus(ERenameStatus eRenameStatus) { m_eRenameStatus = eRenameStatus; }
@@ -637,27 +578,6 @@ public:
void SetFullContentHash(unsigned int iFullContentHash) { m_iFullContentHash = iFullContentHash; }
unsigned int GetFilteredContentHash() { return m_iFilteredContentHash; }
void SetFilteredContentHash(unsigned int iFilteredContentHash) { m_iFilteredContentHash = iFilteredContentHash; }
long long GetDownloadedSize() { return m_lDownloadedSize; }
void SetDownloadedSize(long long lDownloadedSize) { m_lDownloadedSize = lDownloadedSize; }
int GetDownloadSec() { return m_iDownloadSec; }
void SetDownloadSec(int iDownloadSec) { m_iDownloadSec = iDownloadSec; }
int GetPostTotalSec() { return m_iPostTotalSec; }
void SetPostTotalSec(int iPostTotalSec) { m_iPostTotalSec = iPostTotalSec; }
int GetParSec() { return m_iParSec; }
void SetParSec(int iParSec) { m_iParSec = iParSec; }
int GetRepairSec() { return m_iRepairSec; }
void SetRepairSec(int iRepairSec) { m_iRepairSec = iRepairSec; }
int GetUnpackSec() { return m_iUnpackSec; }
void SetUnpackSec(int iUnpackSec) { m_iUnpackSec = iUnpackSec; }
time_t GetDownloadStartTime() { return m_tDownloadStartTime; }
void SetDownloadStartTime(time_t tDownloadStartTime) { m_tDownloadStartTime = tDownloadStartTime; }
void SetReprocess(bool bReprocess) { m_bReprocess = bReprocess; }
bool GetReprocess() { return m_bReprocess; }
time_t GetQueueScriptTime() { return m_tQueueScriptTime; }
void SetQueueScriptTime(time_t tQueueScriptTime) { m_tQueueScriptTime = tQueueScriptTime; }
void SetParFull(bool bParFull) { m_bParFull = bParFull; }
bool GetParFull() { return m_bParFull; }
void CopyFileList(NZBInfo* pSrcNZBInfo);
void UpdateMinMaxTime();
PostInfo* GetPostInfo() { return m_pPostInfo; }
@@ -683,7 +603,6 @@ public:
void Clear();
void Add(NZBInfo* pNZBInfo, bool bAddTop);
void Remove(NZBInfo* pNZBInfo);
NZBInfo* Find(int iID);
};
class PostInfo
@@ -711,8 +630,6 @@ private:
bool m_bWorking;
bool m_bDeleted;
bool m_bRequestParCheck;
bool m_bForceParFull;
bool m_bForceRepair;
EStage m_eStage;
char* m_szProgressLabel;
int m_iFileProgress;
@@ -749,10 +666,6 @@ public:
void SetDeleted(bool bDeleted) { m_bDeleted = bDeleted; }
bool GetRequestParCheck() { return m_bRequestParCheck; }
void SetRequestParCheck(bool bRequestParCheck) { m_bRequestParCheck = bRequestParCheck; }
bool GetForceParFull() { return m_bForceParFull; }
void SetForceParFull(bool bForceParFull) { m_bForceParFull = bForceParFull; }
bool GetForceRepair() { return m_bForceRepair; }
void SetForceRepair(bool bForceRepair) { m_bForceRepair = bForceRepair; }
Thread* GetPostThread() { return m_pPostThread; }
void SetPostThread(Thread* pPostThread) { m_pPostThread = pPostThread; }
void AppendMessage(Message::EKind eKind, const char* szText);
@@ -852,7 +765,6 @@ public:
{
eaNzbFound,
eaNzbAdded,
eaNzbDeleted,
eaFileCompleted,
eaFileDeleted,
eaUrlCompleted
@@ -934,7 +846,7 @@ protected:
static void Loaded() { g_bLoaded = true; }
public:
virtual ~DownloadQueue() {}
virtual ~DownloadQueue() {};
static bool IsLoaded() { return g_bLoaded; }
static DownloadQueue* Lock();
static void Unlock();

View File

@@ -103,58 +103,11 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
}
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
g_pHistoryCoordinator->DeleteDiskFiles(pNZBInfo);
g_pHistoryCoordinator->DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
return;
}
}
// if download has empty dupekey and empty dupescore - check if download queue
// or history have an item with the same name and non empty dupekey or dupescore and
// take these properties from this item
if (Util::EmptyStr(pNZBInfo->GetDupeKey()) && pNZBInfo->GetDupeScore() == 0)
{
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pQueuedNZBInfo = *it;
if (!strcmp(pQueuedNZBInfo->GetName(), pNZBInfo->GetName()) &&
(!Util::EmptyStr(pQueuedNZBInfo->GetDupeKey()) || pQueuedNZBInfo->GetDupeScore() != 0))
{
pNZBInfo->SetDupeKey(pQueuedNZBInfo->GetDupeKey());
pNZBInfo->SetDupeScore(pQueuedNZBInfo->GetDupeScore());
info("Assigning dupekey %s and dupescore %i to %s from existing queue item with the same name",
pNZBInfo->GetDupeKey(), pNZBInfo->GetDupeScore(), pNZBInfo->GetName());
break;
}
}
}
if (Util::EmptyStr(pNZBInfo->GetDupeKey()) && pNZBInfo->GetDupeScore() == 0)
{
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
!strcmp(pHistoryInfo->GetNZBInfo()->GetName(), pNZBInfo->GetName()) &&
(!Util::EmptyStr(pHistoryInfo->GetNZBInfo()->GetDupeKey()) || pHistoryInfo->GetNZBInfo()->GetDupeScore() != 0))
{
pNZBInfo->SetDupeKey(pHistoryInfo->GetNZBInfo()->GetDupeKey());
pNZBInfo->SetDupeScore(pHistoryInfo->GetNZBInfo()->GetDupeScore());
info("Assigning dupekey %s and dupescore %i to %s from existing history item with the same name",
pNZBInfo->GetDupeKey(), pNZBInfo->GetDupeScore(), pNZBInfo->GetName());
break;
}
if (pHistoryInfo->GetKind() == HistoryInfo::hkDup &&
!strcmp(pHistoryInfo->GetDupInfo()->GetName(), pNZBInfo->GetName()) &&
(!Util::EmptyStr(pHistoryInfo->GetDupInfo()->GetDupeKey()) || pHistoryInfo->GetDupInfo()->GetDupeScore() != 0))
{
pNZBInfo->SetDupeKey(pHistoryInfo->GetDupInfo()->GetDupeKey());
pNZBInfo->SetDupeScore(pHistoryInfo->GetDupInfo()->GetDupeScore());
info("Assigning dupekey %s and dupescore %i to %s from existing history item with the same name",
pNZBInfo->GetDupeKey(), pNZBInfo->GetDupeScore(), pNZBInfo->GetName());
break;
}
}
}
// find duplicates in history
bool bSkip = false;
@@ -258,7 +211,7 @@ void DupeCoordinator::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
// Flag saying QueueCoordinator to skip nzb-file
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
g_pHistoryCoordinator->DeleteDiskFiles(pNZBInfo);
g_pHistoryCoordinator->DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
return;
}
@@ -498,67 +451,3 @@ void DupeCoordinator::HistoryCleanup(DownloadQueue* pDownloadQueue, HistoryInfo*
pDownloadQueue->Save();
}
}
DupeCoordinator::EDupeStatus DupeCoordinator::GetDupeStatus(DownloadQueue* pDownloadQueue,
const char* szName, const char* szDupeKey)
{
EDupeStatus eStatuses = dsNone;
// find duplicates in download queue
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
if (SameNameOrKey(szName, szDupeKey, pNZBInfo->GetName(), pNZBInfo->GetDupeKey()))
{
if (pNZBInfo->GetSuccessArticles() + pNZBInfo->GetFailedArticles() > 0)
{
eStatuses = (EDupeStatus)(eStatuses | dsDownloading);
}
else
{
eStatuses = (EDupeStatus)(eStatuses | dsQueued);
}
}
}
// find duplicates in history
for (HistoryList::iterator it = pDownloadQueue->GetHistory()->begin(); it != pDownloadQueue->GetHistory()->end(); it++)
{
HistoryInfo* pHistoryInfo = *it;
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
SameNameOrKey(szName, szDupeKey, pHistoryInfo->GetNZBInfo()->GetName(), pHistoryInfo->GetNZBInfo()->GetDupeKey()))
{
const char* szTextStatus = pHistoryInfo->GetNZBInfo()->MakeTextStatus(true);
if (!strncasecmp(szTextStatus, "SUCCESS", 7))
{
eStatuses = (EDupeStatus)(eStatuses | dsSuccess);
}
else if (!strncasecmp(szTextStatus, "FAILURE", 7))
{
eStatuses = (EDupeStatus)(eStatuses | dsFailure);
}
else if (!strncasecmp(szTextStatus, "WARNING", 7))
{
eStatuses = (EDupeStatus)(eStatuses | dsWarning);
}
}
if (pHistoryInfo->GetKind() == HistoryInfo::hkDup &&
SameNameOrKey(szName, szDupeKey, pHistoryInfo->GetDupInfo()->GetName(), pHistoryInfo->GetDupInfo()->GetDupeKey()))
{
if (pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsSuccess ||
pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood)
{
eStatuses = (EDupeStatus)(eStatuses | dsSuccess);
}
else if (pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsFailed ||
pHistoryInfo->GetDupInfo()->GetStatus() == DupInfo::dsBad)
{
eStatuses = (EDupeStatus)(eStatuses | dsFailure);
}
}
}
return eStatuses;
}

View File

@@ -30,17 +30,6 @@
class DupeCoordinator
{
public:
enum EDupeStatus
{
dsNone = 0,
dsQueued = 1,
dsDownloading = 2,
dsSuccess = 4,
dsWarning = 8,
dsFailure = 16
};
private:
void ReturnBestDupe(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, const char* szNZBName, const char* szDupeKey);
void HistoryCleanup(DownloadQueue* pDownloadQueue, HistoryInfo* pMarkHistoryInfo);
@@ -50,7 +39,6 @@ public:
void NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
void HistoryMark(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, bool bGood);
EDupeStatus GetDupeStatus(DownloadQueue* pDownloadQueue, const char* szName, const char* szDupeKey);
};
#endif

View File

@@ -119,7 +119,7 @@ void HistoryCoordinator::IntervalCheck()
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb)
{
DeleteDiskFiles(pHistoryInfo->GetNZBInfo());
DeleteQueuedFile(pHistoryInfo->GetNZBInfo()->GetQueuedFilename());
}
info("Collection %s removed from history", szNiceName);
@@ -144,24 +144,16 @@ void HistoryCoordinator::IntervalCheck()
DownloadQueue::Unlock();
}
void HistoryCoordinator::DeleteDiskFiles(NZBInfo* pNZBInfo)
void HistoryCoordinator::DeleteQueuedFile(const char* szQueuedFile)
{
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
// delete parked files
g_pDiskState->DiscardFiles(pNZBInfo);
}
pNZBInfo->GetFileList()->Clear();
// delete nzb-file
if (!g_pOptions->GetNzbCleanupDisk())
{
return;
}
// QueuedFile may contain one filename or several filenames separated
// szQueuedFile may contain one filename or several filenames separated
// with "|"-character (for merged groups)
char* szFilename = strdup(pNZBInfo->GetQueuedFilename());
char* szFilename = strdup(szQueuedFile);
char* szEnd = szFilename - 1;
while (szEnd)
@@ -259,7 +251,7 @@ void HistoryCoordinator::HistoryHide(DownloadQueue* pDownloadQueue, HistoryInfo*
pNewHistoryInfo->SetTime(pHistoryInfo->GetTime());
(*pDownloadQueue->GetHistory())[pDownloadQueue->GetHistory()->size() - 1 - rindex] = pNewHistoryInfo;
DeleteDiskFiles(pHistoryInfo->GetNZBInfo());
DeleteQueuedFile(pHistoryInfo->GetNZBInfo()->GetQueuedFilename());
delete pHistoryInfo;
info("Collection %s removed from history", szNiceName);
@@ -337,7 +329,20 @@ void HistoryCoordinator::HistoryDelete(DownloadQueue* pDownloadQueue, HistoryLis
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb)
{
DeleteDiskFiles(pHistoryInfo->GetNZBInfo());
NZBInfo* pNZBInfo = pHistoryInfo->GetNZBInfo();
// delete parked files
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
{
FileInfo* pFileInfo = *it;
g_pDiskState->DiscardFile(pFileInfo);
}
}
pNZBInfo->GetFileList()->Clear();
DeleteQueuedFile(pNZBInfo->GetQueuedFilename());
}
if (pHistoryInfo->GetKind() == HistoryInfo::hkNzb &&
@@ -377,6 +382,7 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis
char szNiceName[1024];
pHistoryInfo->GetName(szNiceName, 1024);
debug("Returning %s from history back to download queue", szNiceName);
bool bUnparked = false;
NZBInfo* pNZBInfo = NULL;
if (bReprocess && pHistoryInfo->GetKind() != HistoryInfo::hkNzb)
@@ -390,7 +396,6 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis
pNZBInfo = pHistoryInfo->GetNZBInfo();
// unpark files
bool bUnparked = false;
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
{
FileInfo* pFileInfo = *it;
@@ -398,12 +403,6 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis
bUnparked = true;
}
if (!(bUnparked || bReprocess))
{
warn("Could not return %s back from history to download queue: history item does not have any files left for download", szNiceName);
return;
}
pDownloadQueue->GetQueue()->push_front(pNZBInfo);
pHistoryInfo->DiscardNZBInfo();
@@ -414,16 +413,10 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis
pNZBInfo->SetUnpackStatus(NZBInfo::usNone);
pNZBInfo->SetCleanupStatus(NZBInfo::csNone);
pNZBInfo->SetRenameStatus(NZBInfo::rsNone);
pNZBInfo->SetPostTotalSec(pNZBInfo->GetPostTotalSec() - pNZBInfo->GetUnpackSec());
pNZBInfo->SetUnpackSec(0);
if (ParCoordinator::FindMainPars(pNZBInfo->GetDestDir(), NULL))
{
pNZBInfo->SetParStatus(NZBInfo::psNone);
pNZBInfo->SetPostTotalSec(pNZBInfo->GetPostTotalSec() - pNZBInfo->GetParSec());
pNZBInfo->SetParSec(0);
pNZBInfo->SetRepairSec(0);
pNZBInfo->SetParFull(false);
}
}
pNZBInfo->SetDeleteStatus(NZBInfo::dsNone);
@@ -435,7 +428,6 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis
{
pNZBInfo->SetMoveStatus(NZBInfo::msNone);
}
pNZBInfo->SetReprocess(bReprocess);
}
if (pHistoryInfo->GetKind() == HistoryInfo::hkUrl)
@@ -445,11 +437,19 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis
pNZBInfo->SetUrlStatus(NZBInfo::lsNone);
pNZBInfo->SetDeleteStatus(NZBInfo::dsNone);
pDownloadQueue->GetQueue()->push_front(pNZBInfo);
bUnparked = true;
}
pDownloadQueue->GetHistory()->erase(itHistory);
// the object "pHistoryInfo" is released few lines later, after the call to "NZBDownloaded"
info("%s returned from history back to download queue", szNiceName);
if (bUnparked || bReprocess)
{
pDownloadQueue->GetHistory()->erase(itHistory);
// the object "pHistoryInfo" is released few lines later, after the call to "NZBDownloaded"
info("%s returned from history back to download queue", szNiceName);
}
else
{
warn("Could not return %s back from history to download queue: history item does not have any files left for download", szNiceName);
}
if (bReprocess)
{
@@ -458,7 +458,10 @@ void HistoryCoordinator::HistoryReturn(DownloadQueue* pDownloadQueue, HistoryLis
g_pPrePostProcessor->NZBDownloaded(pDownloadQueue, pNZBInfo);
}
delete pHistoryInfo;
if (bUnparked || bReprocess)
{
delete pHistoryInfo;
}
}
void HistoryCoordinator::HistoryRedownload(DownloadQueue* pDownloadQueue, HistoryList::iterator itHistory,
@@ -511,19 +514,11 @@ void HistoryCoordinator::HistoryRedownload(DownloadQueue* pDownloadQueue, Histor
}
}
g_pDiskState->DiscardFiles(pNZBInfo);
// reset status fields (which are not reset by "HistoryReturn")
pNZBInfo->SetMoveStatus(NZBInfo::msNone);
pNZBInfo->SetUnpackCleanedUpDisk(false);
pNZBInfo->SetParStatus(NZBInfo::psNone);
pNZBInfo->SetRenameStatus(NZBInfo::rsNone);
pNZBInfo->SetDownloadedSize(0);
pNZBInfo->SetDownloadSec(0);
pNZBInfo->SetPostTotalSec(0);
pNZBInfo->SetParSec(0);
pNZBInfo->SetRepairSec(0);
pNZBInfo->SetUnpackSec(0);
pNZBInfo->ClearCompletedFiles();
pNZBInfo->GetServerStats()->Clear();
pNZBInfo->GetCurrentServerStats()->Clear();
@@ -535,7 +530,11 @@ void HistoryCoordinator::HistoryRedownload(DownloadQueue* pDownloadQueue, Histor
HistoryReturn(pDownloadQueue, itHistory, pHistoryInfo, false);
g_pPrePostProcessor->NZBAdded(pDownloadQueue, pNZBInfo);
if (!bPaused && g_pOptions->GetParCheck() != Options::pcForce)
{
pDownloadQueue->EditEntry(pNZBInfo->GetID(),
DownloadQueue::eaGroupPauseExtraPars, 0, NULL);
}
}
void HistoryCoordinator::HistorySetParameter(HistoryInfo* pHistoryInfo, const char* szText)

View File

@@ -44,7 +44,7 @@ public:
virtual ~HistoryCoordinator();
void AddToHistory(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
bool EditList(DownloadQueue* pDownloadQueue, IDList* pIDList, DownloadQueue::EEditAction eAction, int iOffset, const char* szText);
void DeleteDiskFiles(NZBInfo* pNZBInfo);
void DeleteQueuedFile(const char* szQueuedFile);
void HistoryHide(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo, int rindex);
void Redownload(DownloadQueue* pDownloadQueue, HistoryInfo* pHistoryInfo);
void IntervalCheck();

View File

@@ -461,7 +461,7 @@ void NZBFile::ReadPassword()
// obtain file size.
fseek(pFile , 0 , SEEK_END);
int iSize = (int)ftell(pFile);
int iSize = ftell(pFile);
rewind(pFile);
// reading first 4KB of the file

View File

@@ -47,7 +47,6 @@
#include "Options.h"
#include "ServerPool.h"
#include "ArticleDownloader.h"
#include "ArticleWriter.h"
#include "DiskState.h"
#include "Util.h"
#include "Decoder.h"
@@ -57,7 +56,6 @@ extern Options* g_pOptions;
extern ServerPool* g_pServerPool;
extern DiskState* g_pDiskState;
extern StatMeter* g_pStatMeter;
extern ArticleCache* g_pArticleCache;
bool QueueCoordinator::CoordinatorDownloadQueue::EditEntry(
int ID, EEditAction eAction, int iOffset, const char* szText)
@@ -90,6 +88,7 @@ QueueCoordinator::QueueCoordinator()
m_DownloadQueue.m_pOwner = this;
CoordinatorDownloadQueue::Init(&m_DownloadQueue);
YDecoder::Init();
}
QueueCoordinator::~QueueCoordinator()
@@ -107,6 +106,7 @@ QueueCoordinator::~QueueCoordinator()
m_ActiveDownloads.clear();
CoordinatorDownloadQueue::Final();
YDecoder::Final();
debug("QueueCoordinator destroyed");
}
@@ -149,35 +149,17 @@ void QueueCoordinator::Load()
pDownloadQueue->Save();
// re-save file states into diskstate to update server ids
if (g_pOptions->GetServerMode() && g_pOptions->GetSaveQueue())
if (g_pOptions->GetServerMode() && g_pOptions->GetSaveQueue() && g_pOptions->GetContinuePartial())
{
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
if (g_pOptions->GetContinuePartial())
for (FileList::iterator it2 = pNZBInfo->GetFileList()->begin(); it2 != pNZBInfo->GetFileList()->end(); it2++)
{
for (FileList::iterator it2 = pNZBInfo->GetFileList()->begin(); it2 != pNZBInfo->GetFileList()->end(); it2++)
FileInfo* pFileInfo = *it2;
if (!pFileInfo->GetArticles()->empty())
{
FileInfo* pFileInfo = *it2;
if (!pFileInfo->GetArticles()->empty())
{
g_pDiskState->SaveFileState(pFileInfo, false);
}
}
}
for (CompletedFiles::iterator it2 = pNZBInfo->GetCompletedFiles()->begin(); it2 != pNZBInfo->GetCompletedFiles()->end(); it2++)
{
CompletedFile* pCompletedFile = *it2;
if (pCompletedFile->GetStatus() != CompletedFile::cfSuccess && pCompletedFile->GetID() > 0)
{
FileInfo* pFileInfo = new FileInfo(pCompletedFile->GetID());
if (g_pDiskState->LoadFileState(pFileInfo, g_pServerPool->GetServers(), false))
{
g_pDiskState->SaveFileState(pFileInfo, true);
}
delete pFileInfo;
g_pDiskState->SaveFileState(pFileInfo);
}
}
}
@@ -247,10 +229,6 @@ void QueueCoordinator::Run()
{
g_pStatMeter->EnterLeaveStandBy(bStandBy);
bWasStandBy = bStandBy;
if (bStandBy)
{
SavePartialState();
}
}
// sleep longer in StandBy
@@ -270,10 +248,6 @@ void QueueCoordinator::Run()
// this code should not be called too often, once per second is OK
g_pServerPool->CloseUnusedConnections();
ResetHangingDownloads();
if (!bStandBy)
{
SavePartialState();
}
iResetCounter = 0;
g_pStatMeter->IntervalCheck();
AdjustDownloadsLimit();
@@ -293,8 +267,6 @@ void QueueCoordinator::Run()
}
debug("QueueCoordinator: Downloads are completed");
SavePartialState();
debug("Exiting QueueCoordinator-loop");
}
@@ -346,7 +318,7 @@ void QueueCoordinator::AddNZBFileToQueue(NZBFile* pNZBFile, NZBInfo* pUrlInfo, b
bAllPaused &= pFileInfo->GetPaused();
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->DiscardFile(pFileInfo, true, false, false);
g_pDiskState->DiscardFile(pFileInfo);
}
}
pNZBInfo->SetDeletePaused(bAllPaused);
@@ -459,7 +431,7 @@ void QueueCoordinator::CheckDupeFileInfos(NZBInfo* pNZBInfo)
pNZBInfo->GetFileList()->Remove(pFileInfo);
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->DiscardFile(pFileInfo, true, false, false);
g_pDiskState->DiscardFile(pFileInfo);
}
}
}
@@ -561,17 +533,11 @@ bool QueueCoordinator::GetNextArticle(DownloadQueue* pDownloadQueue, FileInfo* &
iTotalFileCount += pNZBInfo->GetFileList()->size();
}
if (iTotalFileCount > 0)
{
int iArrSize = sizeof(bool) * iTotalFileCount;
pCheckedFiles = (bool*)malloc(iArrSize);
memset(pCheckedFiles, false, iArrSize);
}
}
if (pCheckedFiles)
{
pCheckedFiles[iFileNum] = true;
int iArrSize = sizeof(bool) * iTotalFileCount;
pCheckedFiles = (bool*)malloc(iArrSize);
memset(pCheckedFiles, false, iArrSize);
}
pCheckedFiles[iFileNum] = true;
}
}
@@ -608,7 +574,7 @@ void QueueCoordinator::Update(Subject* Caller, void* Aspect)
{
debug("Notification from ArticleDownloader received");
ArticleDownloader* pArticleDownloader = (ArticleDownloader*)Caller;
ArticleDownloader* pArticleDownloader = (ArticleDownloader*) Caller;
if ((pArticleDownloader->GetStatus() == ArticleDownloader::adFinished) ||
(pArticleDownloader->GetStatus() == ArticleDownloader::adFailed) ||
(pArticleDownloader->GetStatus() == ArticleDownloader::adRetry))
@@ -665,7 +631,10 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
fileCompleted = (int)pFileInfo->GetArticles()->size() == pFileInfo->GetCompletedArticles();
pFileInfo->GetServerStats()->ListOp(pArticleDownloader->GetServerStats(), ServerStatList::soAdd);
pNZBInfo->GetCurrentServerStats()->ListOp(pArticleDownloader->GetServerStats(), ServerStatList::soAdd);
pFileInfo->SetPartialChanged(true);
if (g_pOptions->GetServerMode() && g_pOptions->GetSaveQueue() && g_pOptions->GetContinuePartial())
{
g_pDiskState->SaveFileState(pFileInfo);
}
}
if (!pFileInfo->GetFilenameConfirmed() &&
@@ -686,8 +655,6 @@ void QueueCoordinator::ArticleCompleted(ArticleDownloader* pArticleDownloader)
}
}
pNZBInfo->SetDownloadedSize(pNZBInfo->GetDownloadedSize() + pArticleDownloader->GetDownloadedSize());
bool deleteFileObj = false;
if (fileCompleted && !pFileInfo->GetDeleted())
@@ -787,10 +754,9 @@ void QueueCoordinator::DeleteFileInfo(DownloadQueue* pDownloadQueue, FileInfo* p
StatFileInfo(pFileInfo, bCompleted);
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode() &&
(!bCompleted || (pFileInfo->GetMissedArticles() == 0 && pFileInfo->GetFailedArticles() == 0)))
if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())
{
g_pDiskState->DiscardFile(pFileInfo, true, true, false);
g_pDiskState->DiscardFile(pFileInfo);
}
if (!bCompleted)
@@ -836,33 +802,6 @@ void QueueCoordinator::DiscardDiskFile(FileInfo* pFileInfo)
}
}
void QueueCoordinator::SavePartialState()
{
if (!(g_pOptions->GetServerMode() && g_pOptions->GetSaveQueue() && g_pOptions->GetContinuePartial()))
{
return;
}
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
{
NZBInfo* pNZBInfo = *it;
for (FileList::iterator it2 = pNZBInfo->GetFileList()->begin(); it2 != pNZBInfo->GetFileList()->end(); it2++)
{
FileInfo* pFileInfo = *it2;
if (pFileInfo->GetPartialChanged())
{
debug("Saving partial state for %s", pFileInfo->GetFilename());
g_pDiskState->SaveFileState(pFileInfo, false);
pFileInfo->SetPartialChanged(false);
}
}
}
DownloadQueue::Unlock();
}
void QueueCoordinator::CheckHealth(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo)
{
if (g_pOptions->GetHealthCheck() == Options::hcNone ||
@@ -914,7 +853,7 @@ void QueueCoordinator::LogDebugInfo()
void QueueCoordinator::ResetHangingDownloads()
{
if (g_pOptions->GetTerminateTimeout() == 0 && g_pOptions->GetArticleTimeout() == 0)
if (g_pOptions->GetTerminateTimeout() == 0 && g_pOptions->GetConnectionTimeout() == 0)
{
return;
}
@@ -925,12 +864,11 @@ void QueueCoordinator::ResetHangingDownloads()
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end();)
{
ArticleDownloader* pArticleDownloader = *it;
if (tm - pArticleDownloader->GetLastUpdateTime() > g_pOptions->GetArticleTimeout() + 1 &&
if (tm - pArticleDownloader->GetLastUpdateTime() > g_pOptions->GetConnectionTimeout() + 1 &&
pArticleDownloader->GetStatus() == ArticleDownloader::adRunning)
{
error("Cancelling hanging download %s @ %s", pArticleDownloader->GetInfoName(),
pArticleDownloader->GetConnectionName());
error("Cancelling hanging download %s", pArticleDownloader->GetInfoName());
pArticleDownloader->Stop();
}
@@ -941,21 +879,16 @@ void QueueCoordinator::ResetHangingDownloads()
debug("Terminating hanging download %s", pArticleDownloader->GetInfoName());
if (pArticleDownloader->Terminate())
{
error("Terminated hanging download %s @ %s", pArticleDownloader->GetInfoName(),
pArticleDownloader->GetConnectionName());
error("Terminated hanging download %s", pArticleDownloader->GetInfoName());
pArticleInfo->SetStatus(ArticleInfo::aiUndefined);
}
else
{
error("Could not terminate hanging download %s @ %s", pArticleDownloader->GetInfoName(),
pArticleDownloader->GetConnectionName());
error("Could not terminate hanging download %s", Util::BaseFileName(pArticleInfo->GetResultFilename()));
}
m_ActiveDownloads.erase(it);
pArticleDownloader->GetFileInfo()->SetActiveDownloads(pArticleDownloader->GetFileInfo()->GetActiveDownloads() - 1);
pArticleDownloader->GetFileInfo()->GetNZBInfo()->SetActiveDownloads(pArticleDownloader->GetFileInfo()->GetNZBInfo()->GetActiveDownloads() - 1);
pArticleDownloader->GetFileInfo()->GetNZBInfo()->SetDownloadedSize(pArticleDownloader->GetFileInfo()->GetNZBInfo()->GetDownloadedSize() + pArticleDownloader->GetDownloadedSize());
// it's not safe to destroy pArticleDownloader, because the state of object is unknown
delete pArticleDownloader;
it = m_ActiveDownloads.begin();
@@ -974,27 +907,21 @@ void QueueCoordinator::ResetHangingDownloads()
bool QueueCoordinator::DeleteQueueEntry(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo)
{
pFileInfo->SetDeleted(true);
bool bDownloading = false;
bool hasDownloads = false;
for (ActiveDownloads::iterator it = m_ActiveDownloads.begin(); it != m_ActiveDownloads.end(); it++)
{
ArticleDownloader* pArticleDownloader = *it;
if (pArticleDownloader->GetFileInfo() == pFileInfo)
{
bDownloading = true;
hasDownloads = true;
pArticleDownloader->Stop();
}
}
while (g_pArticleCache->FileBusy(pFileInfo))
{
usleep(20*1000);
}
if (!bDownloading)
if (!hasDownloads)
{
DeleteFileInfo(pDownloadQueue, pFileInfo, false);
}
return bDownloading;
return hasDownloads;
}
bool QueueCoordinator::SetQueueEntryCategory(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, const char* szCategory)
@@ -1013,7 +940,7 @@ bool QueueCoordinator::SetQueueEntryCategory(DownloadQueue* pDownloadQueue, NZBI
pNZBInfo->BuildDestDirName();
bool bDirUnchanged = !strcmp(pNZBInfo->GetDestDir(), szOldDestDir);
bool bOK = bDirUnchanged || ArticleWriter::MoveCompletedFiles(pNZBInfo, szOldDestDir);
bool bOK = bDirUnchanged || ArticleDownloader::MoveCompletedFiles(pNZBInfo, szOldDestDir);
return bOK;
}
@@ -1052,7 +979,7 @@ bool QueueCoordinator::SetQueueEntryName(DownloadQueue* pDownloadQueue, NZBInfo*
pNZBInfo->BuildDestDirName();
bool bDirUnchanged = !strcmp(pNZBInfo->GetDestDir(), szOldDestDir);
bool bOK = bDirUnchanged || ArticleWriter::MoveCompletedFiles(pNZBInfo, szOldDestDir);
bool bOK = bDirUnchanged || ArticleDownloader::MoveCompletedFiles(pNZBInfo, szOldDestDir);
return bOK;
}
@@ -1118,17 +1045,11 @@ bool QueueCoordinator::MergeQueueEntries(DownloadQueue* pDownloadQueue, NZBInfo*
pDestNZBInfo->SetMinTime(pSrcNZBInfo->GetMinTime() < pDestNZBInfo->GetMinTime() ? pSrcNZBInfo->GetMinTime() : pDestNZBInfo->GetMinTime());
pDestNZBInfo->SetMaxTime(pSrcNZBInfo->GetMaxTime() > pDestNZBInfo->GetMaxTime() ? pSrcNZBInfo->GetMaxTime() : pDestNZBInfo->GetMaxTime());
pDestNZBInfo->SetDownloadedSize(pDestNZBInfo->GetDownloadedSize() + pSrcNZBInfo->GetDownloadedSize());
pDestNZBInfo->SetDownloadSec(pDestNZBInfo->GetDownloadSec() + pSrcNZBInfo->GetDownloadSec());
pDestNZBInfo->SetDownloadStartTime((pDestNZBInfo->GetDownloadStartTime() > 0 &&
pDestNZBInfo->GetDownloadStartTime() < pSrcNZBInfo->GetDownloadStartTime()) || pSrcNZBInfo->GetDownloadStartTime() == 0 ?
pDestNZBInfo->GetDownloadStartTime() : pSrcNZBInfo->GetDownloadStartTime());
// reattach completed file items to new NZBInfo-object
for (CompletedFiles::iterator it = pSrcNZBInfo->GetCompletedFiles()->begin(); it != pSrcNZBInfo->GetCompletedFiles()->end(); it++)
for (NZBInfo::Files::iterator it = pSrcNZBInfo->GetCompletedFiles()->begin(); it != pSrcNZBInfo->GetCompletedFiles()->end(); it++)
{
CompletedFile* pCompletedFile = *it;
pDestNZBInfo->GetCompletedFiles()->push_back(pCompletedFile);
char* szFileName = *it;
pDestNZBInfo->GetCompletedFiles()->push_back(szFileName);
}
pSrcNZBInfo->GetCompletedFiles()->clear();

View File

@@ -73,7 +73,6 @@ private:
void ResetHangingDownloads();
void AdjustDownloadsLimit();
void Load();
void SavePartialState();
protected:
virtual void LogDebugInfo();

View File

@@ -234,6 +234,8 @@ bool QueueEditor::EditList(DownloadQueue* pDownloadQueue, IDList* pIDList, NameL
bool QueueEditor::InternEditList(ItemList* pItemList,
IDList* pIDList, DownloadQueue::EEditAction eAction, int iOffset, const char* szText)
{
std::set<NZBInfo*> uniqueNzbs;
ItemList itemList;
if (!pItemList)
{
@@ -622,7 +624,6 @@ bool QueueEditor::EditGroup(NZBInfo* pNZBInfo, DownloadQueue::EEditAction eActio
{
ItemList itemList;
bool bAllPaused = true;
int iID = pNZBInfo->GetID();
// collecting files belonging to group
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
@@ -671,17 +672,7 @@ bool QueueEditor::EditGroup(NZBInfo* pNZBInfo, DownloadQueue::EEditAction eActio
(DownloadQueue::EEditAction)0,
(DownloadQueue::EEditAction)0 };
bool bOK = InternEditList(&itemList, NULL, GroupToFileMap[eAction], iOffset, szText);
if ((eAction == DownloadQueue::eaGroupDelete || eAction == DownloadQueue::eaGroupDupeDelete || eAction == DownloadQueue::eaGroupFinalDelete) &&
// NZBInfo could have been destroyed already
m_pDownloadQueue->GetQueue()->Find(iID))
{
DownloadQueue::Aspect deleteAspect = { DownloadQueue::eaNzbDeleted, m_pDownloadQueue, pNZBInfo, NULL };
m_pDownloadQueue->Notify(&deleteAspect);
}
return bOK;
return InternEditList(&itemList, NULL, GroupToFileMap[eAction], iOffset, szText);
}
void QueueEditor::PauseParsInGroups(ItemList* pItemList, bool bExtraParsOnly)
@@ -910,11 +901,6 @@ void QueueEditor::SetNZBName(NZBInfo* pNZBInfo, const char* szName)
*/
bool QueueEditor::CanCleanupDisk(NZBInfo* pNZBInfo)
{
if (pNZBInfo->GetDeleteStatus() != NZBInfo::dsNone)
{
return true;
}
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
{
FileInfo* pFileInfo = *it;

View File

@@ -39,7 +39,6 @@
#endif
#include <sys/stat.h>
#include <stdio.h>
#include <algorithm>
#include "nzbget.h"
#include "QueueScript.h"
@@ -48,38 +47,6 @@
#include "Util.h"
extern Options* g_pOptions;
extern QueueScriptCoordinator* g_pQueueScriptCoordinator;
static const char* QUEUE_EVENT_NAMES[] = { "FILE_DOWNLOADED", "NZB_ADDED", "NZB_DOWNLOADED" };
class QueueScriptController : public Thread, public NZBScriptController
{
private:
char* m_szNZBName;
char* m_szNZBFilename;
char* m_szUrl;
char* m_szCategory;
char* m_szDestDir;
int m_iID;
int m_iPriority;
NZBParameterList m_Parameters;
int m_iPrefixLen;
Options::Script* m_pScript;
QueueScriptCoordinator::EEvent m_eEvent;
bool m_bMarkBad;
void PrepareParams(const char* szScriptName);
protected:
virtual void ExecuteScript(Options::Script* pScript);
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
virtual ~QueueScriptController();
virtual void Run();
static void StartScript(NZBInfo* pNZBInfo, Options::Script* pScript, QueueScriptCoordinator::EEvent eEvent);
};
/**
* If szStripPrefix is not NULL, only pp-parameters, whose names start with the prefix
@@ -137,7 +104,10 @@ void NZBScriptController::PrepareEnvScript(NZBParameterList* pParameters, const
void NZBScriptController::ExecuteScriptList(const char* szScriptList)
{
for (Options::Scripts::iterator it = g_pOptions->GetScripts()->begin(); it != g_pOptions->GetScripts()->end(); it++)
Options::ScriptList scriptList;
g_pOptions->LoadScriptList(&scriptList);
for (Options::ScriptList::iterator it = scriptList.begin(); it != scriptList.end(); it++)
{
Options::Script* pScript = *it;
@@ -158,16 +128,145 @@ void NZBScriptController::ExecuteScriptList(const char* szScriptList)
}
void ScanScriptController::ExecuteScripts(const char* szNZBFilename,
const char* szUrl, const char* szDirectory, char** pNZBName, char** pCategory,
int* iPriority, NZBParameterList* pParameters, bool* bAddTop, bool* bAddPaused)
{
ScanScriptController* pScriptController = new ScanScriptController();
pScriptController->m_szNZBFilename = szNZBFilename;
pScriptController->m_szUrl = szUrl;
pScriptController->m_szDirectory = szDirectory;
pScriptController->m_pNZBName = pNZBName;
pScriptController->m_pCategory = pCategory;
pScriptController->m_pParameters = pParameters;
pScriptController->m_iPriority = iPriority;
pScriptController->m_bAddTop = bAddTop;
pScriptController->m_bAddPaused = bAddPaused;
pScriptController->m_iPrefixLen = 0;
pScriptController->ExecuteScriptList(g_pOptions->GetScanScript());
delete pScriptController;
}
void ScanScriptController::ExecuteScript(Options::Script* pScript)
{
if (!pScript->GetScanScript() || !Util::FileExists(m_szNZBFilename))
{
return;
}
PrintMessage(Message::mkInfo, "Executing scan-script %s for %s", pScript->GetName(), Util::BaseFileName(m_szNZBFilename));
SetScript(pScript->GetLocation());
SetArgs(NULL, false);
char szInfoName[1024];
snprintf(szInfoName, 1024, "scan-script %s for %s", pScript->GetName(), Util::BaseFileName(m_szNZBFilename));
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
SetLogPrefix(pScript->GetDisplayName());
m_iPrefixLen = strlen(pScript->GetDisplayName()) + 2; // 2 = strlen(": ");
PrepareParams(pScript->GetName());
Execute();
SetLogPrefix(NULL);
}
void ScanScriptController::PrepareParams(const char* szScriptName)
{
ResetEnv();
SetEnvVar("NZBNP_FILENAME", m_szNZBFilename);
SetEnvVar("NZBNP_URL", m_szUrl);
SetEnvVar("NZBNP_NZBNAME", strlen(*m_pNZBName) > 0 ? *m_pNZBName : Util::BaseFileName(m_szNZBFilename));
SetEnvVar("NZBNP_CATEGORY", *m_pCategory);
SetIntEnvVar("NZBNP_PRIORITY", *m_iPriority);
SetIntEnvVar("NZBNP_TOP", *m_bAddTop ? 1 : 0);
SetIntEnvVar("NZBNP_PAUSED", *m_bAddPaused ? 1 : 0);
// remove trailing slash
char szDir[1024];
strncpy(szDir, m_szDirectory, 1024);
szDir[1024-1] = '\0';
int iLen = strlen(szDir);
if (szDir[iLen-1] == PATH_SEPARATOR)
{
szDir[iLen-1] = '\0';
}
SetEnvVar("NZBNP_DIRECTORY", szDir);
PrepareEnvScript(m_pParameters, szScriptName);
}
void ScanScriptController::AddMessage(Message::EKind eKind, const char* szText)
{
const char* szMsgText = szText + m_iPrefixLen;
if (!strncmp(szMsgText, "[NZB] ", 6))
{
debug("Command %s detected", szMsgText + 6);
if (!strncmp(szMsgText + 6, "NZBNAME=", 8))
{
free(*m_pNZBName);
*m_pNZBName = strdup(szMsgText + 6 + 8);
}
else if (!strncmp(szMsgText + 6, "CATEGORY=", 9))
{
free(*m_pCategory);
*m_pCategory = strdup(szMsgText + 6 + 9);
}
else if (!strncmp(szMsgText + 6, "NZBPR_", 6))
{
char* szParam = strdup(szMsgText + 6 + 6);
char* szValue = strchr(szParam, '=');
if (szValue)
{
*szValue = '\0';
m_pParameters->SetParameter(szParam, szValue + 1);
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
free(szParam);
}
else if (!strncmp(szMsgText + 6, "PRIORITY=", 9))
{
*m_iPriority = atoi(szMsgText + 6 + 9);
}
else if (!strncmp(szMsgText + 6, "TOP=", 4))
{
*m_bAddTop = atoi(szMsgText + 6 + 4) != 0;
}
else if (!strncmp(szMsgText + 6, "PAUSED=", 7))
{
*m_bAddPaused = atoi(szMsgText + 6 + 7) != 0;
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
}
else
{
ScriptController::AddMessage(eKind, szText);
}
}
QueueScriptController::~QueueScriptController()
{
free(m_szNZBName);
free(m_szNZBFilename);
free(m_szUrl);
free(m_szCategory);
free(m_szDestDir);
}
void QueueScriptController::StartScript(NZBInfo* pNZBInfo, Options::Script* pScript, QueueScriptCoordinator::EEvent eEvent)
void QueueScriptController::StartScripts(DownloadQueue* pDownloadQueue, NZBInfo *pNZBInfo)
{
QueueScriptController* pScriptController = new QueueScriptController();
@@ -175,14 +274,10 @@ void QueueScriptController::StartScript(NZBInfo* pNZBInfo, Options::Script* pScr
pScriptController->m_szNZBFilename = strdup(pNZBInfo->GetFilename());
pScriptController->m_szUrl = strdup(pNZBInfo->GetURL());
pScriptController->m_szCategory = strdup(pNZBInfo->GetCategory());
pScriptController->m_szDestDir = strdup(pNZBInfo->GetDestDir());
pScriptController->m_iID = pNZBInfo->GetID();
pScriptController->m_iPriority = pNZBInfo->GetPriority();
pScriptController->m_Parameters.CopyFrom(pNZBInfo->GetParameters());
pScriptController->m_pScript = pScript;
pScriptController->m_eEvent = eEvent;
pScriptController->m_iPrefixLen = 0;
pScriptController->m_bMarkBad = false;
pScriptController->SetAutoDestroy(true);
pScriptController->Start();
@@ -190,30 +285,17 @@ void QueueScriptController::StartScript(NZBInfo* pNZBInfo, Options::Script* pScr
void QueueScriptController::Run()
{
ExecuteScript(m_pScript);
SetLogPrefix(NULL);
if (m_bMarkBad)
{
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
NZBInfo* pNZBInfo = pDownloadQueue->GetQueue()->Find(m_iID);
if (pNZBInfo)
{
PrintMessage(Message::mkWarning, "Cancelling download and deleting %s", m_szNZBName);
pNZBInfo->SetDeleteStatus(NZBInfo::dsBad);
pDownloadQueue->EditEntry(m_iID, DownloadQueue::eaGroupDelete, 0, NULL);
}
DownloadQueue::Unlock();
}
g_pQueueScriptCoordinator->CheckQueue();
ExecuteScriptList(g_pOptions->GetQueueScript());
}
void QueueScriptController::ExecuteScript(Options::Script* pScript)
{
PrintMessage(m_eEvent == QueueScriptCoordinator::qeFileDownloaded ? Message::mkDetail : Message::mkInfo,
"Executing queue-script %s for %s", pScript->GetName(), Util::BaseFileName(m_szNZBName));
if (!pScript->GetQueueScript())
{
return;
}
PrintMessage(Message::mkInfo, "Executing queue-script %s for %s", pScript->GetName(), Util::BaseFileName(m_szNZBName));
SetScript(pScript->GetLocation());
SetArgs(NULL, false);
@@ -224,7 +306,6 @@ void QueueScriptController::ExecuteScript(Options::Script* pScript)
SetInfoName(szInfoName);
SetLogPrefix(pScript->GetDisplayName());
m_iPrefixLen = strlen(pScript->GetDisplayName()) + 2; // 2 = strlen(": ");
PrepareParams(pScript->GetName());
Execute();
@@ -239,301 +320,11 @@ void QueueScriptController::PrepareParams(const char* szScriptName)
SetEnvVar("NZBNA_NZBNAME", m_szNZBName);
SetIntEnvVar("NZBNA_NZBID", m_iID);
SetEnvVar("NZBNA_FILENAME", m_szNZBFilename);
SetEnvVar("NZBNA_DIRECTORY", m_szDestDir);
SetEnvVar("NZBNA_URL", m_szUrl);
SetEnvVar("NZBNA_EVENT", "NZB_ADDED");
SetEnvVar("NZBNA_CATEGORY", m_szCategory);
SetIntEnvVar("NZBNA_PRIORITY", m_iPriority);
SetIntEnvVar("NZBNA_LASTID", m_iID); // deprecated
SetEnvVar("NZBNA_EVENT", QUEUE_EVENT_NAMES[m_eEvent]);
PrepareEnvScript(&m_Parameters, szScriptName);
}
void QueueScriptController::AddMessage(Message::EKind eKind, const char* szText)
{
const char* szMsgText = szText + m_iPrefixLen;
if (!strncmp(szMsgText, "[NZB] ", 6))
{
debug("Command %s detected", szMsgText + 6);
if (!strncmp(szMsgText + 6, "NZBPR_", 6))
{
char* szParam = strdup(szMsgText + 6 + 6);
char* szValue = strchr(szParam, '=');
if (szValue)
{
*szValue = '\0';
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
NZBInfo* pNZBInfo = pDownloadQueue->GetQueue()->Find(m_iID);
if (pNZBInfo)
{
pNZBInfo->GetParameters()->SetParameter(szParam, szValue + 1);
}
DownloadQueue::Unlock();
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
free(szParam);
}
else if (!strncmp(szMsgText + 6, "MARK=BAD", 8))
{
m_bMarkBad = true;
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
NZBInfo* pNZBInfo = pDownloadQueue->GetQueue()->Find(m_iID);
if (pNZBInfo)
{
SetLogPrefix(NULL);
PrintMessage(Message::mkWarning, "Marking %s as bad", m_szNZBName);
SetLogPrefix(m_pScript->GetDisplayName());
pNZBInfo->SetMarkStatus(NZBInfo::ksBad);
}
DownloadQueue::Unlock();
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
}
else
{
ScriptController::AddMessage(eKind, szText);
}
}
QueueScriptCoordinator::QueueItem::QueueItem(int iNZBID, Options::Script* pScript, EEvent eEvent)
{
m_iNZBID = iNZBID;
m_pScript = pScript;
m_eEvent = eEvent;
}
QueueScriptCoordinator::QueueScriptCoordinator()
{
m_pCurItem = NULL;
}
QueueScriptCoordinator::~QueueScriptCoordinator()
{
delete m_pCurItem;
for (Queue::iterator it = m_Queue.begin(); it != m_Queue.end(); )
{
delete *it;
}
}
void QueueScriptCoordinator::InitOptions()
{
m_bHasQueueScripts = false;
for (Options::Scripts::iterator it = g_pOptions->GetScripts()->begin(); it != g_pOptions->GetScripts()->end(); it++)
{
Options::Script* pScript = *it;
if (pScript->GetQueueScript())
{
m_bHasQueueScripts = true;
break;
}
}
}
void QueueScriptCoordinator::EnqueueScript(NZBInfo* pNZBInfo, EEvent eEvent)
{
if (!m_bHasQueueScripts)
{
return;
}
m_mutexQueue.Lock();
if (eEvent == qeNzbDownloaded)
{
// delete all other queued scripts for this nzb
for (Queue::iterator it = m_Queue.begin(); it != m_Queue.end(); )
{
QueueItem* pQueueItem = *it;
if (pQueueItem->GetNZBID() == pNZBInfo->GetID())
{
delete pQueueItem;
it = m_Queue.erase(it);
continue;
}
it++;
}
}
// respect option "EventInterval"
time_t tCurTime = time(NULL);
if (eEvent == qeFileDownloaded &&
(g_pOptions->GetEventInterval() == -1 ||
(g_pOptions->GetEventInterval() > 0 && tCurTime - pNZBInfo->GetQueueScriptTime() > 0 &&
(int)(tCurTime - pNZBInfo->GetQueueScriptTime()) < g_pOptions->GetEventInterval())))
{
m_mutexQueue.Unlock();
return;
}
for (Options::Scripts::iterator it = g_pOptions->GetScripts()->begin(); it != g_pOptions->GetScripts()->end(); it++)
{
Options::Script* pScript = *it;
if (!pScript->GetQueueScript())
{
continue;
}
bool bUseScript = false;
// check queue-scripts
const char* szQueueScript = g_pOptions->GetQueueScript();
if (!Util::EmptyStr(szQueueScript))
{
// split szQueueScript into tokens
Tokenizer tok(szQueueScript, ",;");
while (const char* szScriptName = tok.Next())
{
if (Util::SameFilename(szScriptName, pScript->GetName()))
{
bUseScript = true;
break;
}
}
}
// check post-processing-scripts
if (!bUseScript)
{
for (NZBParameterList::iterator it = pNZBInfo->GetParameters()->begin(); it != pNZBInfo->GetParameters()->end(); it++)
{
NZBParameter* pParameter = *it;
const char* szVarname = pParameter->GetName();
if (strlen(szVarname) > 0 && szVarname[0] != '*' && szVarname[strlen(szVarname)-1] == ':' &&
(!strcasecmp(pParameter->GetValue(), "yes") ||
!strcasecmp(pParameter->GetValue(), "on") ||
!strcasecmp(pParameter->GetValue(), "1")))
{
char szScriptName[1024];
strncpy(szScriptName, szVarname, 1024);
szScriptName[1024-1] = '\0';
szScriptName[strlen(szScriptName)-1] = '\0'; // remove trailing ':'
if (Util::SameFilename(szScriptName, pScript->GetName()))
{
bUseScript = true;
break;
}
}
}
}
bUseScript &= Util::EmptyStr(pScript->GetQueueEvents()) || strstr(pScript->GetQueueEvents(), QUEUE_EVENT_NAMES[eEvent]);
if (bUseScript)
{
bool bAlreadyQueued = false;
if (eEvent == qeFileDownloaded)
{
// check if this script is already queued for this nzb
for (Queue::iterator it2 = m_Queue.begin(); it2 != m_Queue.end(); it2++)
{
QueueItem* pQueueItem = *it2;
if (pQueueItem->GetNZBID() == pNZBInfo->GetID() && pQueueItem->GetScript() == pScript)
{
bAlreadyQueued = true;
break;
}
}
}
if (!bAlreadyQueued)
{
QueueItem* pQueueItem = new QueueItem(pNZBInfo->GetID(), pScript, eEvent);
if (m_pCurItem)
{
m_Queue.push_back(pQueueItem);
}
else
{
StartScript(pNZBInfo, pQueueItem);
}
}
pNZBInfo->SetQueueScriptTime(time(NULL));
}
}
m_mutexQueue.Unlock();
}
void QueueScriptCoordinator::CheckQueue()
{
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
m_mutexQueue.Lock();
delete m_pCurItem;
m_pCurItem = NULL;
NZBInfo* pCurNZBInfo = NULL;
Queue::iterator itCurItem = m_Queue.end();
for (Queue::iterator it = m_Queue.begin(); it != m_Queue.end(); )
{
QueueItem* pQueueItem = *it;
NZBInfo* pNZBInfo = pDownloadQueue->GetQueue()->Find(pQueueItem->GetNZBID());
// in a case this nzb must not be processed further - delete queue script from queue
if (!pNZBInfo || pNZBInfo->GetDeleteStatus() != NZBInfo::dsNone ||
pNZBInfo->GetMarkStatus() == NZBInfo::ksBad)
{
delete pQueueItem;
it = m_Queue.erase(it);
continue;
}
if (!m_pCurItem || pQueueItem->GetEvent() > m_pCurItem->GetEvent())
{
m_pCurItem = pQueueItem;
itCurItem = it;
pCurNZBInfo = pNZBInfo;
}
it++;
}
if (m_pCurItem)
{
m_Queue.erase(itCurItem);
StartScript(pCurNZBInfo, m_pCurItem);
}
m_mutexQueue.Unlock();
DownloadQueue::Unlock();
}
void QueueScriptCoordinator::StartScript(NZBInfo* pNZBInfo, QueueItem* pQueueItem)
{
m_pCurItem = pQueueItem;
QueueScriptController::StartScript(pNZBInfo, pQueueItem->GetScript(), pQueueItem->GetEvent());
}
bool QueueScriptCoordinator::HasJob(int iNZBID)
{
m_mutexQueue.Lock();
bool bWorking = m_pCurItem && m_pCurItem->GetNZBID() == iNZBID;
if (!bWorking)
{
for (Queue::iterator it = m_Queue.begin(); it != m_Queue.end(); it++)
{
QueueItem* pQueueItem = *it;
bWorking = pQueueItem->GetNZBID() == iNZBID;
if (bWorking)
{
break;
}
}
}
m_mutexQueue.Unlock();
return bWorking;
}

View File

@@ -26,8 +26,6 @@
#ifndef QUEUESCRIPT_H
#define QUEUESCRIPT_H
#include <list>
#include "Script.h"
#include "Thread.h"
#include "DownloadInfo.h"
@@ -42,46 +40,52 @@ protected:
virtual void ExecuteScript(Options::Script* pScript) = 0;
};
class QueueScriptCoordinator
class ScanScriptController : public NZBScriptController
{
public:
enum EEvent
{
qeFileDownloaded, // lowest priority
qeNzbAdded,
qeNzbDownloaded // highest priority
};
private:
class QueueItem
{
private:
int m_iNZBID;
Options::Script* m_pScript;
EEvent m_eEvent;
public:
QueueItem(int iNZBID, Options::Script* pScript, EEvent eEvent);
int GetNZBID() { return m_iNZBID; }
Options::Script* GetScript() { return m_pScript; }
EEvent GetEvent() { return m_eEvent; }
};
const char* m_szNZBFilename;
const char* m_szUrl;
const char* m_szDirectory;
char** m_pNZBName;
char** m_pCategory;
int* m_iPriority;
NZBParameterList* m_pParameters;
bool* m_bAddTop;
bool* m_bAddPaused;
int m_iPrefixLen;
typedef std::list<QueueItem*> Queue;
Queue m_Queue;
Mutex m_mutexQueue;
QueueItem* m_pCurItem;
bool m_bHasQueueScripts;
void PrepareParams(const char* szScriptName);
void StartScript(NZBInfo* pNZBInfo, QueueItem* pQueueItem);
protected:
virtual void ExecuteScript(Options::Script* pScript);
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
QueueScriptCoordinator();
~QueueScriptCoordinator();
void InitOptions();
void EnqueueScript(NZBInfo* pNZBInfo, EEvent eEvent);
void CheckQueue();
bool HasJob(int iNZBID);
static void ExecuteScripts(const char* szNZBFilename, const char* szUrl,
const char* szDirectory, char** pNZBName, char** pCategory, int* iPriority,
NZBParameterList* pParameters, bool* bAddTop, bool* bAddPaused);
};
class QueueScriptController : public Thread, public NZBScriptController
{
private:
char* m_szNZBName;
char* m_szNZBFilename;
char* m_szUrl;
char* m_szCategory;
int m_iID;
int m_iPriority;
NZBParameterList m_Parameters;
void PrepareParams(const char* szScriptName);
protected:
virtual void ExecuteScript(Options::Script* pScript);
public:
virtual ~QueueScriptController();
virtual void Run();
static void StartScripts(DownloadQueue* pDownloadQueue, NZBInfo *pNZBInfo);
};
#endif

View File

@@ -51,198 +51,6 @@
extern QueueCoordinator* g_pQueueCoordinator;
extern Options* g_pOptions;
extern Scanner* g_pScanner;
class ScanScriptController : public NZBScriptController
{
private:
const char* m_szNZBFilename;
const char* m_szUrl;
const char* m_szDirectory;
char** m_pNZBName;
char** m_pCategory;
int* m_iPriority;
NZBParameterList* m_pParameters;
bool* m_bAddTop;
bool* m_bAddPaused;
char** m_pDupeKey;
int* m_iDupeScore;
EDupeMode* m_eDupeMode;
int m_iPrefixLen;
void PrepareParams(const char* szScriptName);
protected:
virtual void ExecuteScript(Options::Script* pScript);
virtual void AddMessage(Message::EKind eKind, const char* szText);
public:
static void ExecuteScripts(const char* szNZBFilename, const char* szUrl,
const char* szDirectory, char** pNZBName, char** pCategory, int* iPriority,
NZBParameterList* pParameters, bool* bAddTop, bool* bAddPaused,
char** pDupeKey, int* iDupeScore, EDupeMode* eDupeMode);
};
void ScanScriptController::ExecuteScripts(const char* szNZBFilename,
const char* szUrl, const char* szDirectory, char** pNZBName, char** pCategory,
int* iPriority, NZBParameterList* pParameters, bool* bAddTop, bool* bAddPaused,
char** pDupeKey, int* iDupeScore, EDupeMode* eDupeMode)
{
ScanScriptController* pScriptController = new ScanScriptController();
pScriptController->m_szNZBFilename = szNZBFilename;
pScriptController->m_szUrl = szUrl;
pScriptController->m_szDirectory = szDirectory;
pScriptController->m_pNZBName = pNZBName;
pScriptController->m_pCategory = pCategory;
pScriptController->m_pParameters = pParameters;
pScriptController->m_iPriority = iPriority;
pScriptController->m_bAddTop = bAddTop;
pScriptController->m_bAddPaused = bAddPaused;
pScriptController->m_pDupeKey = pDupeKey;
pScriptController->m_iDupeScore = iDupeScore;
pScriptController->m_eDupeMode = eDupeMode;
pScriptController->m_iPrefixLen = 0;
pScriptController->ExecuteScriptList(g_pOptions->GetScanScript());
delete pScriptController;
}
void ScanScriptController::ExecuteScript(Options::Script* pScript)
{
if (!pScript->GetScanScript() || !Util::FileExists(m_szNZBFilename))
{
return;
}
PrintMessage(Message::mkInfo, "Executing scan-script %s for %s", pScript->GetName(), Util::BaseFileName(m_szNZBFilename));
SetScript(pScript->GetLocation());
SetArgs(NULL, false);
char szInfoName[1024];
snprintf(szInfoName, 1024, "scan-script %s for %s", pScript->GetName(), Util::BaseFileName(m_szNZBFilename));
szInfoName[1024-1] = '\0';
SetInfoName(szInfoName);
SetLogPrefix(pScript->GetDisplayName());
m_iPrefixLen = strlen(pScript->GetDisplayName()) + 2; // 2 = strlen(": ");
PrepareParams(pScript->GetName());
Execute();
SetLogPrefix(NULL);
}
void ScanScriptController::PrepareParams(const char* szScriptName)
{
ResetEnv();
SetEnvVar("NZBNP_FILENAME", m_szNZBFilename);
SetEnvVar("NZBNP_URL", m_szUrl);
SetEnvVar("NZBNP_NZBNAME", strlen(*m_pNZBName) > 0 ? *m_pNZBName : Util::BaseFileName(m_szNZBFilename));
SetEnvVar("NZBNP_CATEGORY", *m_pCategory);
SetIntEnvVar("NZBNP_PRIORITY", *m_iPriority);
SetIntEnvVar("NZBNP_TOP", *m_bAddTop ? 1 : 0);
SetIntEnvVar("NZBNP_PAUSED", *m_bAddPaused ? 1 : 0);
SetEnvVar("NZBNP_DUPEKEY", *m_pDupeKey);
SetIntEnvVar("NZBNP_DUPESCORE", *m_iDupeScore);
const char* szDupeModeName[] = { "SCORE", "ALL", "FORCE" };
SetEnvVar("NZBNP_DUPEMODE", szDupeModeName[*m_eDupeMode]);
// remove trailing slash
char szDir[1024];
strncpy(szDir, m_szDirectory, 1024);
szDir[1024-1] = '\0';
int iLen = strlen(szDir);
if (szDir[iLen-1] == PATH_SEPARATOR)
{
szDir[iLen-1] = '\0';
}
SetEnvVar("NZBNP_DIRECTORY", szDir);
PrepareEnvScript(m_pParameters, szScriptName);
}
void ScanScriptController::AddMessage(Message::EKind eKind, const char* szText)
{
const char* szMsgText = szText + m_iPrefixLen;
if (!strncmp(szMsgText, "[NZB] ", 6))
{
debug("Command %s detected", szMsgText + 6);
if (!strncmp(szMsgText + 6, "NZBNAME=", 8))
{
free(*m_pNZBName);
*m_pNZBName = strdup(szMsgText + 6 + 8);
}
else if (!strncmp(szMsgText + 6, "CATEGORY=", 9))
{
free(*m_pCategory);
*m_pCategory = strdup(szMsgText + 6 + 9);
g_pScanner->InitPPParameters(*m_pCategory, m_pParameters, true);
}
else if (!strncmp(szMsgText + 6, "NZBPR_", 6))
{
char* szParam = strdup(szMsgText + 6 + 6);
char* szValue = strchr(szParam, '=');
if (szValue)
{
*szValue = '\0';
m_pParameters->SetParameter(szParam, szValue + 1);
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
free(szParam);
}
else if (!strncmp(szMsgText + 6, "PRIORITY=", 9))
{
*m_iPriority = atoi(szMsgText + 6 + 9);
}
else if (!strncmp(szMsgText + 6, "TOP=", 4))
{
*m_bAddTop = atoi(szMsgText + 6 + 4) != 0;
}
else if (!strncmp(szMsgText + 6, "PAUSED=", 7))
{
*m_bAddPaused = atoi(szMsgText + 6 + 7) != 0;
}
else if (!strncmp(szMsgText + 6, "DUPEKEY=", 8))
{
free(*m_pDupeKey);
*m_pDupeKey = strdup(szMsgText + 6 + 8);
}
else if (!strncmp(szMsgText + 6, "DUPESCORE=", 10))
{
*m_iDupeScore = atoi(szMsgText + 6 + 10);
}
else if (!strncmp(szMsgText + 6, "DUPEMODE=", 9))
{
const char* szDupeMode = szMsgText + 6 + 9;
if (strcasecmp(szDupeMode, "score") && strcasecmp(szDupeMode, "all") && strcasecmp(szDupeMode, "force"))
{
error("Invalid value \"%s\" for command \"DUPEMODE\" received from %s", szDupeMode, GetInfoName());
return;
}
*m_eDupeMode = !strcasecmp(szDupeMode, "all") ? dmAll :
!strcasecmp(szDupeMode, "force") ? dmForce : dmScore;
}
else
{
error("Invalid command \"%s\" received from %s", szMsgText, GetInfoName());
}
}
else
{
ScriptController::AddMessage(eKind, szText);
}
}
Scanner::FileData::FileData(const char* szFilename)
{
@@ -541,7 +349,7 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
int iPriority = 0;
bool bAddTop = false;
bool bAddPaused = false;
char* szDupeKey = strdup("");
const char* szDupeKey = NULL;
int iDupeScore = 0;
EDupeMode eDupeMode = dmScore;
EAddStatus eAddStatus = asSkipped;
@@ -561,8 +369,7 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
free(szNZBCategory);
szNZBCategory = strdup(pQueueData->GetCategory());
iPriority = pQueueData->GetPriority();
free(szDupeKey);
szDupeKey = strdup(pQueueData->GetDupeKey());
szDupeKey = pQueueData->GetDupeKey();
iDupeScore = pQueueData->GetDupeScore();
eDupeMode = pQueueData->GetDupeMode();
bAddTop = pQueueData->GetAddTop();
@@ -572,7 +379,7 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
}
}
InitPPParameters(szNZBCategory, pParameters, false);
InitPPParameters(szNZBCategory, pParameters);
bool bExists = true;
@@ -580,8 +387,7 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
{
ScanScriptController::ExecuteScripts(szFullFilename,
pUrlInfo ? pUrlInfo->GetURL() : "", szDirectory,
&szNZBName, &szNZBCategory, &iPriority, pParameters, &bAddTop,
&bAddPaused, &szDupeKey, &iDupeScore, &eDupeMode);
&szNZBName, &szNZBCategory, &iPriority, pParameters, &bAddTop, &bAddPaused);
bExists = Util::FileExists(szFullFilename);
if (bExists && strcasecmp(szExtension, ".nzb"))
{
@@ -621,7 +427,6 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
free(szNZBName);
free(szNZBCategory);
free(szDupeKey);
if (pQueueData)
{
@@ -630,39 +435,27 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil
}
}
void Scanner::InitPPParameters(const char* szCategory, NZBParameterList* pParameters, bool bReset)
void Scanner::InitPPParameters(const char* szCategory, NZBParameterList* pParameters)
{
bool bUnpack = g_pOptions->GetUnpack();
const char* szPostScript = g_pOptions->GetPostScript();
if (!Util::EmptyStr(szCategory))
if (szCategory && *szCategory)
{
Options::Category* pCategory = g_pOptions->FindCategory(szCategory, false);
if (pCategory)
{
bUnpack = pCategory->GetUnpack();
if (!Util::EmptyStr(pCategory->GetPostScript()))
if (pCategory->GetPostScript() && *pCategory->GetPostScript())
{
szPostScript = pCategory->GetPostScript();
}
}
}
if (bReset)
{
for (Options::Scripts::iterator it = g_pOptions->GetScripts()->begin(); it != g_pOptions->GetScripts()->end(); it++)
{
Options::Script* pScript = *it;
char szParam[1024];
snprintf(szParam, 1024, "%s:", pScript->GetName());
szParam[1024-1] = '\0';
pParameters->SetParameter(szParam, NULL);
}
}
pParameters->SetParameter("*Unpack:", bUnpack ? "yes" : "no");
if (!Util::EmptyStr(szPostScript))
if (szPostScript && *szPostScript)
{
// split szPostScript into tokens and create pp-parameter for each token
Tokenizer tok(szPostScript, ",;");
@@ -855,8 +648,8 @@ Scanner::EAddStatus Scanner::AddExternalFile(const char* szNZBName, const char*
}
char* szUseCategory = strdup(szCategory ? szCategory : "");
Options::Category *pCategory = g_pOptions->FindCategory(szUseCategory, true);
if (pCategory && strcmp(szUseCategory, pCategory->GetName()))
Options::Category *pCategory = g_pOptions->FindCategory(szCategory, true);
if (pCategory && strcmp(szCategory, pCategory->GetName()))
{
free(szUseCategory);
szUseCategory = strdup(pCategory->GetName());

View File

@@ -130,7 +130,7 @@ public:
const char* szDupeKey, int iDupeScore, EDupeMode eDupeMode,
NZBParameterList* pParameters, bool bAddTop, bool bAddPaused, NZBInfo* pUrlInfo,
const char* szFileName, const char* szBuffer, int iBufSize, int* pNZBID);
void InitPPParameters(const char* szCategory, NZBParameterList* pParameters, bool bReset);
void InitPPParameters(const char* szCategory, NZBParameterList* pParameters);
};
#endif

View File

@@ -80,7 +80,7 @@ void UrlDownloader::ProcessHeader(const char* szLine)
char* szValue = strchr(szModLine, ':');
if (szValue)
{
*szValue = '\0';
*szValue = NULL;
szValue++;
while (*szValue == ' ') szValue++;
Util::Trim(szValue);

View File

@@ -459,7 +459,6 @@ void ListBinCommand::Execute()
pListAnswer->m_iPausedSizeLo = htonl(iPausedSizeLo);
pListAnswer->m_iPausedSizeHi = htonl(iPausedSizeHi);
pListAnswer->m_iPausedCount = htonl(pNZBInfo->GetPausedFileCount());
pListAnswer->m_iRemainingParCount = htonl(pNZBInfo->GetRemainingParCount());
pListAnswer->m_iPriority = htonl(pNZBInfo->GetPriority());
pListAnswer->m_bMatch = htonl(bMatchGroup && (!pRegEx || pRegEx->Match(pNZBInfo->GetName())));
pListAnswer->m_iFilenameLen = htonl(strlen(pNZBInfo->GetFilename()) + 1);

View File

@@ -27,7 +27,7 @@
#ifndef MESSAGEBASE_H
#define MESSAGEBASE_H
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6225; // = "nzb-XX" (protocol version)
static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6224; // = "nzb-XX" (protocol version)
static const int NZBREQUESTFILENAMESIZE = 512;
static const int NZBREQUESTPASSWORDSIZE = 32;
@@ -173,7 +173,6 @@ struct SNZBListResponseNZBEntry
int32_t m_iPausedSizeLo; // Size of npaused files in bytes, Low 32-bits of 64-bit value
int32_t m_iPausedSizeHi; // Size of paused files in bytes, High 32-bits of 64-bit value
int32_t m_iPausedCount; // Number of paused files
int32_t m_iRemainingParCount; // Number of remaining par-files
int32_t m_iPriority; // Download priority
int32_t m_bMatch; // 1 - group matches the pattern (only when Request has eRemoteMatchModeRegEx)
int32_t m_iFilenameLen; // Length of Filename-string (m_szFilename), following to this record

View File

@@ -101,12 +101,19 @@ void RemoteClient::perror(const char * msg)
bool RemoteClient::InitConnection()
{
// Create a connection to the server
m_pConnection = new Connection(g_pOptions->GetControlIP(), g_pOptions->GetControlPort(), false);
const char *szControlIP = g_pOptions->GetControlIP();
if (!strcmp(szControlIP, "0.0.0.0"))
{
szControlIP = "127.0.0.1";
}
m_pConnection = new Connection(szControlIP, g_pOptions->GetControlPort(), false);
bool OK = m_pConnection->Connect();
if (!OK)
{
printf("Unable to send request to nzbget-server at %s (port %i)\n", g_pOptions->GetControlIP(), g_pOptions->GetControlPort());
printf("Unable to send request to nzbserver at %s (port %i)\n", szControlIP, g_pOptions->GetControlPort());
}
return OK;
}
@@ -235,7 +242,6 @@ void RemoteClient::BuildFileList(SNZBListResponse* pListResponse, const char* pT
pNZBInfo->SetRemainingSize(Util::JoinInt64(ntohl(pListAnswer->m_iRemainingSizeHi), ntohl(pListAnswer->m_iRemainingSizeLo)));
pNZBInfo->SetPausedSize(Util::JoinInt64(ntohl(pListAnswer->m_iPausedSizeHi), ntohl(pListAnswer->m_iPausedSizeLo)));
pNZBInfo->SetPausedFileCount(ntohl(pListAnswer->m_iPausedCount));
pNZBInfo->SetRemainingParCount(ntohl(pListAnswer->m_iRemainingParCount));
pNZBInfo->SetFilename(szFileName);
pNZBInfo->SetName(szName);
pNZBInfo->SetDestDir(szDestDir);

View File

@@ -34,7 +34,6 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifndef WIN32
#include <unistd.h>
#include <sys/socket.h>
@@ -100,7 +99,7 @@ void RemoteServer::Run()
m_pConnection = new Connection(g_pOptions->GetControlIP(),
m_bTLS ? g_pOptions->GetSecurePort() : g_pOptions->GetControlPort(),
m_bTLS);
m_pConnection->SetTimeout(g_pOptions->GetUrlTimeout());
m_pConnection->SetTimeout(g_pOptions->GetConnectionTimeout());
m_pConnection->SetSuppressErrors(false);
bBind = m_pConnection->Bind();
}
@@ -181,7 +180,7 @@ void RequestProcessor::Run()
int iSignature = 0;
if (!m_pConnection->Recv((char*)&iSignature, 4))
{
debug("Could not read request signature");
debug("Could not read request signature, request received on port %i from %s", m_bTLS ? g_pOptions->GetSecurePort() : g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr());
return;
}

View File

@@ -189,7 +189,7 @@ void WebProcessor::Execute()
char* pw = strchr(szAuthInfo, ':');
if (pw) *pw++ = '\0';
if ((strlen(g_pOptions->GetControlUsername()) > 0 && strcmp(szAuthInfo, g_pOptions->GetControlUsername())) ||
(pw && strcmp(pw, g_pOptions->GetControlPassword())))
strcmp(pw, g_pOptions->GetControlPassword()))
{
warn("Request received on port %i from %s, but username or password invalid (%s:%s)",
g_pOptions->GetControlPort(), m_pConnection->GetRemoteAddr(), szAuthInfo, pw);

View File

@@ -49,7 +49,6 @@
#include "Util.h"
#include "Maintenance.h"
#include "StatMeter.h"
#include "ArticleWriter.h"
extern Options* g_pOptions;
extern Scanner* g_pScanner;
@@ -57,7 +56,6 @@ extern FeedCoordinator* g_pFeedCoordinator;
extern ServerPool* g_pServerPool;
extern Maintenance* g_pMaintenance;
extern StatMeter* g_pStatMeter;
extern ArticleCache* g_pArticleCache;
extern void ExitProc();
extern void Reload();
@@ -1167,9 +1165,6 @@ void StatusXmlCommand::Execute()
"<member><name>DownloadedSizeLo</name><value><i4>%u</i4></value></member>\n"
"<member><name>DownloadedSizeHi</name><value><i4>%u</i4></value></member>\n"
"<member><name>DownloadedSizeMB</name><value><i4>%i</i4></value></member>\n"
"<member><name>ArticleCacheLo</name><value><i4>%u</i4></value></member>\n"
"<member><name>ArticleCacheHi</name><value><i4>%u</i4></value></member>\n"
"<member><name>ArticleCacheMB</name><value><i4>%i</i4></value></member>\n"
"<member><name>DownloadRate</name><value><i4>%i</i4></value></member>\n"
"<member><name>AverageDownloadRate</name><value><i4>%i</i4></value></member>\n"
"<member><name>DownloadLimit</name><value><i4>%i</i4></value></member>\n"
@@ -1208,9 +1203,6 @@ void StatusXmlCommand::Execute()
"\"DownloadedSizeLo\" : %u,\n"
"\"DownloadedSizeHi\" : %u,\n"
"\"DownloadedSizeMB\" : %i,\n"
"\"ArticleCacheLo\" : %u,\n"
"\"ArticleCacheHi\" : %u,\n"
"\"ArticleCacheMB\" : %i,\n"
"\"DownloadRate\" : %i,\n"
"\"AverageDownloadRate\" : %i,\n"
"\"DownloadLimit\" : %i,\n"
@@ -1271,11 +1263,6 @@ void StatusXmlCommand::Execute()
Util::SplitInt64(iForcedSize, &iForcedSizeHi, &iForcedSizeLo);
int iForcedMBytes = (int)(iForcedSize / 1024 / 1024);
long long iArticleCache = g_pArticleCache->GetAllocated();
unsigned long iArticleCacheHi, iArticleCacheLo;
Util::SplitInt64(iArticleCache, &iArticleCacheHi, &iArticleCacheLo);
int iArticleCacheMBytes = (int)(iArticleCache / 1024 / 1024);
int iDownloadRate = (int)(g_pStatMeter->CalcCurrentDownloadSpeed());
int iDownloadLimit = (int)(g_pOptions->GetDownloadRate());
bool bDownloadPaused = g_pOptions->GetPauseDownload();
@@ -1303,8 +1290,7 @@ void StatusXmlCommand::Execute()
snprintf(szContent, 3072, IsJson() ? JSON_STATUS_START : XML_STATUS_START,
iRemainingSizeLo, iRemainingSizeHi, iRemainingMBytes, iForcedSizeLo,
iForcedSizeHi, iForcedMBytes, iDownloadedSizeLo, iDownloadedSizeHi,
iDownloadedMBytes, iArticleCacheLo, iArticleCacheHi, iArticleCacheMBytes,
iDownloadRate, iAverageDownloadRate, iDownloadLimit, iThreadCount,
iDownloadedMBytes, iDownloadRate, iAverageDownloadRate, iDownloadLimit, iThreadCount,
iPostJobCount, iPostJobCount, iUrlCount, iUpTimeSec, iDownloadTimeSec,
BoolToStr(bDownloadPaused), BoolToStr(bDownloadPaused), BoolToStr(bDownloadPaused),
BoolToStr(bServerStandBy), BoolToStr(bPostPaused), BoolToStr(bScanPaused),
@@ -1571,8 +1557,6 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo)
"<member><name>FileSizeHi</name><value><i4>%u</i4></value></member>\n"
"<member><name>FileSizeMB</name><value><i4>%i</i4></value></member>\n"
"<member><name>FileCount</name><value><i4>%i</i4></value></member>\n"
"<member><name>MinPostTime</name><value><i4>%i</i4></value></member>\n"
"<member><name>MaxPostTime</name><value><i4>%i</i4></value></member>\n"
"<member><name>TotalArticles</name><value><i4>%i</i4></value></member>\n"
"<member><name>SuccessArticles</name><value><i4>%i</i4></value></member>\n"
"<member><name>FailedArticles</name><value><i4>%i</i4></value></member>\n"
@@ -1582,16 +1566,8 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo)
"<member><name>DupeScore</name><value><i4>%i</i4></value></member>\n"
"<member><name>DupeMode</name><value><string>%s</string></value></member>\n"
"<member><name>Deleted</name><value><boolean>%s</boolean></value></member>\n" // deprecated, use "DeleteStatus" instead
"<member><name>DownloadedSizeLo</name><value><i4>%u</i4></value></member>\n"
"<member><name>DownloadedSizeHi</name><value><i4>%u</i4></value></member>\n"
"<member><name>DownloadedSizeMB</name><value><i4>%i</i4></value></member>\n"
"<member><name>DownloadTimeSec</name><value><i4>%i</i4></value></member>\n"
"<member><name>PostTotalTimeSec</name><value><i4>%i</i4></value></member>\n"
"<member><name>ParTimeSec</name><value><i4>%i</i4></value></member>\n"
"<member><name>RepairTimeSec</name><value><i4>%i</i4></value></member>\n"
"<member><name>UnpackTimeSec</name><value><i4>%i</i4></value></member>\n"
"<member><name>Parameters</name><value><array><data>\n";
const char* XML_NZB_ITEM_SCRIPT_START =
"</data></array></value></member>\n"
"<member><name>ScriptStatuses</name><value><array><data>\n";
@@ -1624,8 +1600,6 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo)
"\"FileSizeHi\" : %u,\n"
"\"FileSizeMB\" : %i,\n"
"\"FileCount\" : %i,\n"
"\"MinPostTime\" : %i,\n"
"\"MaxPostTime\" : %i,\n"
"\"TotalArticles\" : %i,\n"
"\"SuccessArticles\" : %i,\n"
"\"FailedArticles\" : %i,\n"
@@ -1635,16 +1609,8 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo)
"\"DupeScore\" : %i,\n"
"\"DupeMode\" : \"%s\",\n"
"\"Deleted\" : %s,\n" // deprecated, use "DeleteStatus" instead
"\"DownloadedSizeLo\" : %u,\n"
"\"DownloadedSizeHi\" : %u,\n"
"\"DownloadedSizeMB\" : %i,\n"
"\"DownloadTimeSec\" : %i,\n"
"\"PostTotalTimeSec\" : %i,\n"
"\"ParTimeSec\" : %i,\n"
"\"RepairTimeSec\" : %i,\n"
"\"UnpackTimeSec\" : %i,\n"
"\"Parameters\" : [\n";
const char* JSON_NZB_ITEM_SCRIPT_START =
"],\n"
"\"ScriptStatuses\" : [\n";
@@ -1699,7 +1665,7 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo)
const char* szUnpackStatusName[] = { "NONE", "NONE", "FAILURE", "SUCCESS", "SPACE", "PASSWORD" };
const char* szMoveStatusName[] = { "NONE", "FAILURE", "SUCCESS" };
const char* szScriptStatusName[] = { "NONE", "FAILURE", "SUCCESS" };
const char* szDeleteStatusName[] = { "NONE", "MANUAL", "HEALTH", "DUPE", "BAD" };
const char* szDeleteStatusName[] = { "NONE", "MANUAL", "HEALTH", "DUPE" };
const char* szMarkStatusName[] = { "NONE", "BAD", "GOOD" };
const char* szUrlStatusName[] = { "NONE", "UNKNOWN", "SUCCESS", "FAILURE", "UNKNOWN", "SCAN_SKIPPED", "SCAN_FAILURE" };
const char* szDupeModeName[] = { "SCORE", "ALL", "FORCE" };
@@ -1710,11 +1676,7 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo)
unsigned long iFileSizeHi, iFileSizeLo, iFileSizeMB;
Util::SplitInt64(pNZBInfo->GetSize(), &iFileSizeHi, &iFileSizeLo);
iFileSizeMB = (int)(pNZBInfo->GetSize() / 1024 / 1024);
unsigned long iDownloadedSizeHi, iDownloadedSizeLo, iDownloadedSizeMB;
Util::SplitInt64(pNZBInfo->GetDownloadedSize(), &iDownloadedSizeHi, &iDownloadedSizeLo);
iDownloadedSizeMB = (int)(pNZBInfo->GetDownloadedSize() / 1024 / 1024);
char* xmlURL = EncodeStr(pNZBInfo->GetURL());
char* xmlNZBFilename = EncodeStr(pNZBInfo->GetFilename());
char* xmlNZBNicename = EncodeStr(pNZBInfo->GetName());
@@ -1732,15 +1694,11 @@ void NzbInfoXmlCommand::AppendNZBInfoFields(NZBInfo* pNZBInfo)
szDeleteStatusName[pNZBInfo->GetDeleteStatus()], szMarkStatusName[pNZBInfo->GetMarkStatus()],
szUrlStatusName[pNZBInfo->GetUrlStatus()],
iFileSizeLo, iFileSizeHi, iFileSizeMB, pNZBInfo->GetFileCount(),
pNZBInfo->GetMinTime(), pNZBInfo->GetMaxTime(),
pNZBInfo->GetTotalArticles(), pNZBInfo->GetCurrentSuccessArticles(), pNZBInfo->GetCurrentFailedArticles(),
pNZBInfo->CalcHealth(), pNZBInfo->CalcCriticalHealth(false),
xmlDupeKey, pNZBInfo->GetDupeScore(), szDupeModeName[pNZBInfo->GetDupeMode()],
BoolToStr(pNZBInfo->GetDeleteStatus() != NZBInfo::dsNone),
iDownloadedSizeLo, iDownloadedSizeHi, iDownloadedSizeMB, pNZBInfo->GetDownloadSec(),
pNZBInfo->GetPostInfo() && pNZBInfo->GetPostInfo()->GetStartTime() ? time(NULL) - pNZBInfo->GetPostInfo()->GetStartTime() : pNZBInfo->GetPostTotalSec(),
pNZBInfo->GetParSec(), pNZBInfo->GetRepairSec(), pNZBInfo->GetUnpackSec());
BoolToStr(pNZBInfo->GetDeleteStatus() != NZBInfo::dsNone));
free(xmlURL);
free(xmlNZBNicename);
free(xmlNZBFilename);
@@ -1828,14 +1786,14 @@ void NzbInfoXmlCommand::AppendPostInfoFields(PostInfo* pPostInfo, int iLogEntrie
const char* XML_GROUPQUEUE_ITEM_START =
"<member><name>PostInfoText</name><value><string>%s</string></value></member>\n"
"<member><name>PostStageProgress</name><value><i4>%i</i4></value></member>\n"
"<member><name>PostTotalTimeSec</name><value><i4>%i</i4></value></member>\n"
"<member><name>PostStageTimeSec</name><value><i4>%i</i4></value></member>\n";
// PostTotalTimeSec is printed by method "AppendNZBInfoFields"
const char* XML_POSTQUEUE_ITEM_START =
"<member><name>ProgressLabel</name><value><string>%s</string></value></member>\n"
"<member><name>StageProgress</name><value><i4>%i</i4></value></member>\n"
"<member><name>StageTimeSec</name><value><i4>%i</i4></value></member>\n"
"<member><name>TotalTimeSec</name><value><i4>%i</i4></value></member>\n";
"<member><name>TotalTimeSec</name><value><i4>%i</i4></value></member>\n"
"<member><name>StageTimeSec</name><value><i4>%i</i4></value></member>\n";
const char* XML_LOG_START =
"<member><name>Log</name><value><array><data>\n";
@@ -1846,13 +1804,14 @@ void NzbInfoXmlCommand::AppendPostInfoFields(PostInfo* pPostInfo, int iLogEntrie
const char* JSON_GROUPQUEUE_ITEM_START =
"\"PostInfoText\" : \"%s\",\n"
"\"PostStageProgress\" : %i,\n"
"\"PostTotalTimeSec\" : %i,\n"
"\"PostStageTimeSec\" : %i,\n";
const char* JSON_POSTQUEUE_ITEM_START =
"\"ProgressLabel\" : \"%s\",\n"
"\"StageProgress\" : %i,\n"
"\"StageTimeSec\" : %i,\n"
"\"TotalTimeSec\" : %i,\n";
"\"TotalTimeSec\" : %i,\n"
"\"StageTimeSec\" : %i,\n";
const char* JSON_LOG_START =
"\"Log\" : [\n";
@@ -1891,8 +1850,8 @@ void NzbInfoXmlCommand::AppendPostInfoFields(PostInfo* pPostInfo, int iLogEntrie
char* xmlProgressLabel = EncodeStr(pPostInfo->GetProgressLabel());
snprintf(szItemBuf, iItemBufSize, szItemStart, xmlProgressLabel, pPostInfo->GetStageProgress(),
pPostInfo->GetStageTime() ? tCurTime - pPostInfo->GetStageTime() : 0,
pPostInfo->GetStartTime() ? tCurTime - pPostInfo->GetStartTime() : 0);
pPostInfo->GetStartTime() ? tCurTime - pPostInfo->GetStartTime() : 0,
pPostInfo->GetStageTime() ? tCurTime - pPostInfo->GetStageTime() : 0);
free(xmlProgressLabel);
}
@@ -1967,6 +1926,8 @@ void ListGroupsXmlCommand::Execute()
"<member><name>PausedSizeMB</name><value><i4>%i</i4></value></member>\n"
"<member><name>RemainingFileCount</name><value><i4>%i</i4></value></member>\n"
"<member><name>RemainingParCount</name><value><i4>%i</i4></value></member>\n"
"<member><name>MinPostTime</name><value><i4>%i</i4></value></member>\n"
"<member><name>MaxPostTime</name><value><i4>%i</i4></value></member>\n"
"<member><name>MinPriority</name><value><i4>%i</i4></value></member>\n"
"<member><name>MaxPriority</name><value><i4>%i</i4></value></member>\n"
"<member><name>ActiveDownloads</name><value><i4>%i</i4></value></member>\n"
@@ -1987,6 +1948,8 @@ void ListGroupsXmlCommand::Execute()
"\"PausedSizeMB\" : %i,\n"
"\"RemainingFileCount\" : %i,\n"
"\"RemainingParCount\" : %i,\n"
"\"MinPostTime\" : %i,\n"
"\"MaxPostTime\" : %i,\n"
"\"MinPriority\" : %i,\n"
"\"MaxPriority\" : %i,\n"
"\"ActiveDownloads\" : %i,\n"
@@ -2016,8 +1979,8 @@ void ListGroupsXmlCommand::Execute()
snprintf(szItemBuf, iItemBufSize, IsJson() ? JSON_LIST_ITEM_START : XML_LIST_ITEM_START,
pNZBInfo->GetID(), pNZBInfo->GetID(), iRemainingSizeLo, iRemainingSizeHi, iRemainingSizeMB,
iPausedSizeLo, iPausedSizeHi, iPausedSizeMB, (int)pNZBInfo->GetFileList()->size(),
pNZBInfo->GetRemainingParCount(), pNZBInfo->GetPriority(), pNZBInfo->GetPriority(),
pNZBInfo->GetActiveDownloads(), szStatus);
pNZBInfo->GetRemainingParCount(), pNZBInfo->GetMinTime(), pNZBInfo->GetMaxTime(),
pNZBInfo->GetPriority(), pNZBInfo->GetPriority(), pNZBInfo->GetActiveDownloads(), szStatus);
szItemBuf[iItemBufSize-1] = '\0';
if (IsJson() && index++ > 0)
@@ -2316,7 +2279,7 @@ void DownloadXmlCommand::Execute()
if (bV13)
{
BuildIntResponse(bOK ? iNZBID : -1);
BuildIntResponse(bOK ? iNZBID : 0);
}
else
{
@@ -2882,9 +2845,7 @@ void SaveConfigXmlCommand::Execute()
char* szName;
char* szValue;
char* szDummy;
while ((IsJson() && NextParamAsStr(&szDummy) && NextParamAsStr(&szName) &&
NextParamAsStr(&szDummy) && NextParamAsStr(&szValue)) ||
(!IsJson() && NextParamAsStr(&szName) && NextParamAsStr(&szValue)))
while (NextParamAsStr(&szDummy) && NextParamAsStr(&szName) && NextParamAsStr(&szDummy) && NextParamAsStr(&szValue))
{
DecodeStr(szName);
DecodeStr(szValue);
@@ -2899,8 +2860,7 @@ void SaveConfigXmlCommand::Execute()
BuildBoolResponse(bOK);
}
// struct[] configtemplates(bool loadFromDisk)
// parameter "loadFromDisk" is optional (new in v14)
// struct[] configtemplates()
void ConfigTemplatesXmlCommand::Execute()
{
const char* XML_CONFIG_ITEM =
@@ -2925,20 +2885,13 @@ void ConfigTemplatesXmlCommand::Execute()
"\"Template\" : \"%s\"\n"
"}";
bool bLoadFromDisk = false;
NextParamAsBool(&bLoadFromDisk);
Options::ConfigTemplates* pConfigTemplates = new Options::ConfigTemplates();
Options::ConfigTemplates* pConfigTemplates = g_pOptions->GetConfigTemplates();
if (bLoadFromDisk)
if (!g_pOptions->LoadConfigTemplates(pConfigTemplates))
{
pConfigTemplates = new Options::ConfigTemplates();
if (!g_pOptions->LoadConfigTemplates(pConfigTemplates))
{
BuildErrorResponse(3, "Could not read configuration templates");
delete pConfigTemplates;
return;
}
BuildErrorResponse(3, "Could not read configuration templates");
delete pConfigTemplates;
return;
}
AppendResponse(IsJson() ? "[\n" : "<array><data>\n");
@@ -2978,10 +2931,7 @@ void ConfigTemplatesXmlCommand::Execute()
free(szItemBuf);
}
if (bLoadFromDisk)
{
delete pConfigTemplates;
}
delete pConfigTemplates;
AppendResponse(IsJson() ? "\n]" : "</data></array>\n");
}

View File

@@ -2,7 +2,7 @@
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007-2013 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
@@ -32,7 +32,6 @@
#include "win32.h"
#else
#include <pthread.h>
#include <unistd.h>
#endif
#include <stdlib.h>
@@ -53,7 +52,6 @@ Log::Log()
m_Messages.clear();
m_iIDGen = 0;
m_szLogFilename = NULL;
m_tLastWritten = 0;
#ifdef DEBUG
m_bExtraDebug = Util::FileExists("extradebug");
#endif
@@ -84,57 +82,48 @@ void Log::LogDebugInfo()
void Log::Filelog(const char* msg, ...)
{
if (!m_szLogFilename)
if (m_szLogFilename)
{
return;
}
char tmp2[1024];
char tmp2[1024];
va_list ap;
va_start(ap, msg);
vsnprintf(tmp2, 1024, msg, ap);
tmp2[1024-1] = '\0';
va_end(ap);
va_list ap;
va_start(ap, msg);
vsnprintf(tmp2, 1024, msg, ap);
tmp2[1024-1] = '\0';
va_end(ap);
time_t rawtime = time(NULL) + g_pOptions->GetTimeCorrection();
char szTime[50];
time_t rawtime;
time(&rawtime);
rawtime += g_pOptions->GetTimeCorrection();
char szTime[50];
#ifdef HAVE_CTIME_R_3
ctime_r(&rawtime, szTime, 50);
ctime_r(&rawtime, szTime, 50);
#else
ctime_r(&rawtime, szTime);
ctime_r(&rawtime, szTime);
#endif
szTime[50-1] = '\0';
szTime[strlen(szTime) - 1] = '\0'; // trim LF
szTime[50-1] = '\0';
szTime[strlen(szTime) - 1] = '\0'; // trim LF
if ((int)rawtime/86400 != (int)m_tLastWritten/86400 && g_pOptions->GetWriteLog() == Options::wlRotate)
{
RotateLog();
}
m_tLastWritten = rawtime;
FILE* file = fopen(m_szLogFilename, FOPEN_ABP);
if (file)
{
FILE* file = fopen(m_szLogFilename, FOPEN_ABP);
if (file)
{
#ifdef WIN32
unsigned long iProcessId = GetCurrentProcessId();
unsigned long iThreadId = GetCurrentThreadId();
unsigned long iThreadId = GetCurrentThreadId();
#else
unsigned long iProcessId = (unsigned long)getpid();
unsigned long iThreadId = (unsigned long)pthread_self();
unsigned long iThreadId = (unsigned long)pthread_self();
#endif
#ifdef DEBUG
fprintf(file, "%s\t%lu\t%lu\t%s%s", szTime, iProcessId, iThreadId, tmp2, LINE_ENDING);
fprintf(file, "%s\t%lu\t%s%s", szTime, iThreadId, tmp2, LINE_ENDING);
#else
fprintf(file, "%s\t%s%s", szTime, tmp2, LINE_ENDING);
fprintf(file, "%s\t%s%s", szTime, tmp2, LINE_ENDING);
#endif
fclose(file);
}
else
{
perror(m_szLogFilename);
fclose(file);
}
else
{
perror(m_szLogFilename);
}
}
}
@@ -177,14 +166,14 @@ void debug(const char* msg, ...)
}
Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetDebugTarget() : Options::mtScreen;
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
g_pLog->AppendMessage(Message::mkDebug, tmp2);
}
if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth)
{
g_pLog->Filelog("DEBUG\t%s", tmp2);
}
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
g_pLog->AppendMessage(Message::mkDebug, tmp2);
}
g_pLog->m_mutexLog.Unlock();
}
@@ -203,14 +192,14 @@ void error(const char* msg, ...)
g_pLog->m_mutexLog.Lock();
Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetErrorTarget() : Options::mtBoth;
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
g_pLog->AppendMessage(Message::mkError, tmp2);
}
if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth)
{
g_pLog->Filelog("ERROR\t%s", tmp2);
}
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
g_pLog->AppendMessage(Message::mkError, tmp2);
}
g_pLog->m_mutexLog.Unlock();
}
@@ -228,14 +217,14 @@ void warn(const char* msg, ...)
g_pLog->m_mutexLog.Lock();
Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetWarningTarget() : Options::mtScreen;
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
g_pLog->AppendMessage(Message::mkWarning, tmp2);
}
if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth)
{
g_pLog->Filelog("WARNING\t%s", tmp2);
}
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
g_pLog->AppendMessage(Message::mkWarning, tmp2);
}
g_pLog->m_mutexLog.Unlock();
}
@@ -253,14 +242,14 @@ void info(const char* msg, ...)
g_pLog->m_mutexLog.Lock();
Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetInfoTarget() : Options::mtScreen;
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
g_pLog->AppendMessage(Message::mkInfo, tmp2);
}
if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth)
{
g_pLog->Filelog("INFO\t%s", tmp2);
}
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
g_pLog->AppendMessage(Message::mkInfo, tmp2);
}
g_pLog->m_mutexLog.Unlock();
}
@@ -278,14 +267,14 @@ void detail(const char* msg, ...)
g_pLog->m_mutexLog.Lock();
Options::EMessageTarget eMessageTarget = g_pOptions ? g_pOptions->GetDetailTarget() : Options::mtScreen;
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
g_pLog->AppendMessage(Message::mkDetail, tmp2);
}
if (eMessageTarget == Options::mtLog || eMessageTarget == Options::mtBoth)
{
g_pLog->Filelog("DETAIL\t%s", tmp2);
}
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
{
g_pLog->AppendMessage(Message::mkDetail, tmp2);
}
g_pLog->m_mutexLog.Unlock();
}
@@ -377,82 +366,6 @@ void Log::ResetLog()
remove(g_pOptions->GetLogFile());
}
void Log::RotateLog()
{
char szDirectory[1024];
strncpy(szDirectory, g_pOptions->GetLogFile(), 1024);
szDirectory[1024-1] = '\0';
// split the full filename into path, basename and extension
char* szBaseName = Util::BaseFileName(szDirectory);
if (szBaseName > szDirectory)
{
szBaseName[-1] = '\0';
}
char szBaseExt[250];
char* szExt = strrchr(szBaseName, '.');
if (szExt && szExt > szBaseName)
{
strncpy(szBaseExt, szExt, 250);
szBaseExt[250-1] = '\0';
szExt[0] = '\0';
}
else
{
szBaseExt[0] = '\0';
}
char szFileMask[1024];
snprintf(szFileMask, 1024, "%s-####-##-##%s", szBaseName, szBaseExt);
szFileMask[1024-1] = '\0';
time_t tCurTime = time(NULL) + g_pOptions->GetTimeCorrection();
int iCurDay = (int)tCurTime / 86400;
char szFullFilename[1024];
WildMask mask(szFileMask, true);
DirBrowser dir(szDirectory);
while (const char* filename = dir.Next())
{
if (mask.Match(filename))
{
snprintf(szFullFilename, 1024, "%s%c%s", szDirectory, PATH_SEPARATOR, filename);
szFullFilename[1024-1] = '\0';
struct tm tm;
memset(&tm, 0, sizeof(tm));
tm.tm_year = atoi(filename + mask.GetMatchStart(0)) - 1900;
tm.tm_mon = atoi(filename + mask.GetMatchStart(1)) - 1;
tm.tm_mday = atoi(filename + mask.GetMatchStart(2));
time_t tFileTime = Util::Timegm(&tm);
int iFileDay = (int)tFileTime / 86400;
if (iFileDay <= iCurDay - g_pOptions->GetRotateLog())
{
char szMessage[1024];
snprintf(szMessage, 1024, "Deleting old log-file %s\n", filename);
szMessage[1024-1] = '\0';
g_pLog->AppendMessage(Message::mkInfo, szMessage);
remove(szFullFilename);
}
}
}
struct tm tm;
gmtime_r(&tCurTime, &tm);
snprintf(szFullFilename, 1024, "%s%c%s-%i-%.2i-%.2i%s", szDirectory, PATH_SEPARATOR,
szBaseName, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, szBaseExt);
szFullFilename[1024-1] = '\0';
free(m_szLogFilename);
m_szLogFilename = strdup(szFullFilename);
#ifdef WIN32
WebUtil::Utf8ToAnsi(m_szLogFilename, strlen(m_szLogFilename) + 1);
#endif
}
/*
* During intializing stage (when options were not read yet) all messages
* are saved in screen log, even if they shouldn't (according to options).
@@ -466,17 +379,12 @@ void Log::InitOptions()
{
const char* szMessageType[] = { "INFO", "WARNING", "ERROR", "DEBUG", "DETAIL"};
if (g_pOptions->GetWriteLog() != Options::wlNone && g_pOptions->GetLogFile())
if (g_pOptions->GetCreateLog() && g_pOptions->GetLogFile())
{
m_szLogFilename = strdup(g_pOptions->GetLogFile());
#ifdef WIN32
WebUtil::Utf8ToAnsi(m_szLogFilename, strlen(m_szLogFilename) + 1);
#endif
if (g_pOptions->GetServerMode() && g_pOptions->GetWriteLog() == Options::wlReset)
{
g_pLog->ResetLog();
}
}
m_iIDGen = 0;

View File

@@ -96,14 +96,12 @@ private:
Mutex m_mutexDebug;
char* m_szLogFilename;
unsigned int m_iIDGen;
time_t m_tLastWritten;
#ifdef DEBUG
bool m_bExtraDebug;
#endif
void Filelog(const char* msg, ...);
void AppendMessage(Message::EKind eKind, const char* szText);
void RotateLog();
friend void error(const char* msg, ...);
friend void warn(const char* msg, ...);

View File

@@ -38,15 +38,12 @@
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#else
#include <io.h>
#endif
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <algorithm>
#include "nzbget.h"
#include "Script.h"
@@ -60,9 +57,6 @@ extern char** environ;
extern Options* g_pOptions;
extern char* (*g_szEnvironmentVariables)[];
ScriptController::RunningScripts ScriptController::m_RunningScripts;
Mutex ScriptController::m_mutexRunning;
#ifndef WIN32
#define CHILD_WATCHDOG 1
#endif
@@ -201,12 +195,7 @@ ScriptController::ScriptController()
m_szLogPrefix = NULL;
m_bTerminated = false;
m_bDetached = false;
m_hProcess = 0;
m_environmentStrings.InitFromCurrentProcess();
m_mutexRunning.Lock();
m_RunningScripts.push_back(this);
m_mutexRunning.Unlock();
}
ScriptController::~ScriptController()
@@ -219,10 +208,6 @@ ScriptController::~ScriptController()
}
free(m_szArgs);
}
m_mutexRunning.Lock();
m_RunningScripts.erase(std::find(m_RunningScripts.begin(), m_RunningScripts.end(), this));
m_mutexRunning.Unlock();
}
void ScriptController::ResetEnv()
@@ -627,11 +612,6 @@ void ScriptController::Terminate()
#ifdef WIN32
BOOL bOK = TerminateProcess(m_hProcess, -1);
if (bOK)
{
// wait 60 seconds for process to terminate
WaitForSingleObject(m_hProcess, 60 * 1000);
}
#else
pid_t hKillProcess = m_hProcess;
if (getpgid(hKillProcess) == hKillProcess)
@@ -639,7 +619,7 @@ void ScriptController::Terminate()
// if the child process has its own group (setsid() was successful), kill the whole group
hKillProcess = -hKillProcess;
}
bool bOK = hKillProcess && kill(hKillProcess, SIGKILL) == 0;
bool bOK = kill(hKillProcess, SIGKILL) == 0;
#endif
if (bOK)
@@ -654,20 +634,6 @@ void ScriptController::Terminate()
debug("Stopped %s", m_szInfoName);
}
void ScriptController::TerminateAll()
{
m_mutexRunning.Lock();
for (RunningScripts::iterator it = m_RunningScripts.begin(); it != m_RunningScripts.end(); it++)
{
ScriptController* pScript = *it;
if (pScript->m_hProcess && !pScript->m_bDetached)
{
pScript->Terminate();
}
}
m_mutexRunning.Unlock();
}
void ScriptController::Detach()
{
debug("Detaching %s", m_szInfoName);

View File

@@ -28,7 +28,6 @@
#include <vector>
#include "Thread.h"
#include "Log.h"
class EnvironmentStrings
@@ -72,10 +71,6 @@ private:
pid_t m_hProcess;
#endif
typedef std::vector<ScriptController*> RunningScripts;
static RunningScripts m_RunningScripts;
static Mutex m_mutexRunning;
protected:
void ProcessOutput(char* szText);
virtual bool ReadLine(char* szBuf, int iBufSize, FILE* pStream);
@@ -92,7 +87,6 @@ public:
int Execute();
void Terminate();
void Detach();
static void TerminateAll();
void SetScript(const char* szScript) { m_szScript = szScript; }
const char* GetScript() { return m_szScript; }

View File

@@ -38,14 +38,12 @@
#include <errno.h>
#include <ctype.h>
#ifdef WIN32
#include <io.h>
#include <direct.h>
#include <WinIoCtl.h>
#else
#include <unistd.h>
#include <sys/statvfs.h>
#include <pwd.h>
#include <dirent.h>
#endif
#ifdef HAVE_REGEX_H
#include <regex.h>
@@ -179,70 +177,30 @@ const char* DirBrowser::Next()
#else
#ifdef DIRBROWSER_SNAPSHOT
DirBrowser::DirBrowser(const char* szPath, bool bSnapshot)
#else
DirBrowser::DirBrowser(const char* szPath)
#endif
{
#ifdef DIRBROWSER_SNAPSHOT
m_bSnapshot = bSnapshot;
if (m_bSnapshot)
{
DirBrowser dir(szPath, false);
while (const char* filename = dir.Next())
{
m_Snapshot.push_back(strdup(filename));
}
m_itSnapshot = m_Snapshot.begin();
}
else
#endif
{
m_pDir = opendir(szPath);
}
m_pDir = opendir(szPath);
}
DirBrowser::~DirBrowser()
{
#ifdef DIRBROWSER_SNAPSHOT
if (m_bSnapshot)
if (m_pDir)
{
for (FileList::iterator it = m_Snapshot.begin(); it != m_Snapshot.end(); it++)
{
delete *it;
}
}
else
#endif
{
if (m_pDir)
{
closedir((DIR*)m_pDir);
}
closedir(m_pDir);
}
}
const char* DirBrowser::Next()
{
#ifdef DIRBROWSER_SNAPSHOT
if (m_bSnapshot)
if (m_pDir)
{
return m_itSnapshot == m_Snapshot.end() ? NULL : *m_itSnapshot++;
}
else
#endif
{
if (m_pDir)
m_pFindData = readdir(m_pDir);
if (m_pFindData)
{
m_pFindData = readdir((DIR*)m_pDir);
if (m_pFindData)
{
return m_pFindData->d_name;
}
return m_pFindData->d_name;
}
return NULL;
}
return NULL;
}
#endif
@@ -436,7 +394,7 @@ bool Util::LoadFileIntoBuffer(const char* szFileName, char** pBuffer, int* pBuff
// obtain file size.
fseek(pFile , 0 , SEEK_END);
int iSize = (int)ftell(pFile);
int iSize = ftell(pFile);
rewind(pFile);
// allocate memory to contain the whole file.
@@ -472,7 +430,7 @@ bool Util::SaveBufferIntoFile(const char* szFileName, const char* szBuffer, int
return iWrittenBytes == iBufLen;
}
bool Util::CreateSparseFile(const char* szFilename, long long iSize)
bool Util::CreateSparseFile(const char* szFilename, int iSize)
{
bool bOK = false;
#ifdef WIN32
@@ -484,9 +442,7 @@ bool Util::CreateSparseFile(const char* szFilename, long long iSize)
DWORD dwBytesReturned;
DeviceIoControl(hFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
LARGE_INTEGER iSize64;
iSize64.QuadPart = iSize;
SetFilePointerEx(hFile, iSize64, NULL, FILE_END);
SetFilePointer(hFile, iSize, NULL, FILE_END);
SetEndOfFile(hFile);
CloseHandle(hFile);
bOK = true;
@@ -500,7 +456,7 @@ bool Util::CreateSparseFile(const char* szFilename, long long iSize)
}
// there are no reliable function to expand file on POSIX, so we must try different approaches,
// starting with the fastest one and hoping it will work
// 1) set file size using function "truncate" (it is fast, if it works)
// 1) set file size using function "truncate" (it is fast, if works)
truncate(szFilename, iSize);
// check if it worked
pFile = fopen(szFilename, FOPEN_AB);
@@ -940,7 +896,7 @@ bool Util::ExpandHomePath(const char* szFilename, char* szBuffer, int iBufSize)
}
else
{
strncpy(szBuffer, szFilename ? szFilename : "", iBufSize);
strncpy(szBuffer, szFilename, iBufSize);
szBuffer[iBufSize - 1] = '\0';
}
@@ -1262,7 +1218,7 @@ bool Util::RegReadStr(HKEY hKey, const char* szKeyName, const char* szValueName,
/* From boost */
inline int is_leap(int year)
inline int32_t is_leap(int32_t year)
{
if(year % 400 == 0)
return 1;
@@ -1272,19 +1228,19 @@ inline int is_leap(int year)
return 1;
return 0;
}
inline int days_from_0(int year)
inline int32_t days_from_0(int32_t year)
{
year--;
return 365 * year + (year / 400) - (year/100) + (year / 4);
}
inline int days_from_1970(int year)
inline int32_t days_from_1970(int32_t year)
{
static const int days_from_0_to_1970 = days_from_0(1970);
return days_from_0(year) - days_from_0_to_1970;
}
inline int days_from_1jan(int year,int month,int day)
inline int32_t days_from_1jan(int32_t year,int32_t month,int32_t day)
{
static const int days[2][12] =
static const int32_t days[2][12] =
{
{ 0,31,59,90,120,151,181,212,243,273,304,334},
{ 0,31,60,91,121,152,182,213,244,274,305,335}
@@ -1331,171 +1287,6 @@ time_t Util::Timegm(tm const *t)
return internal_timegm(t);
}
static unsigned long 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.
*/
unsigned long Util::Crc32m(unsigned long startCrc, unsigned char *block, unsigned long length)
{
register unsigned long crc = startCrc;
for (unsigned long i = 0; i < length; i++)
{
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32_tab[(crc ^ *block++) & 0xFF];
}
return crc;
}
unsigned long Util::Crc32(unsigned char *block, unsigned long 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) */
unsigned long gf2_matrix_times(unsigned long *mat, unsigned long vec)
{
unsigned long sum;
sum = 0;
while (vec) {
if (vec & 1)
sum ^= *mat;
vec >>= 1;
mat++;
}
return sum;
}
void gf2_matrix_square(unsigned long *square, unsigned long *mat)
{
int n;
for (n = 0; n < GF2_DIM; n++)
square[n] = gf2_matrix_times(mat, mat[n]);
}
unsigned long Util::Crc32Combine(unsigned long crc1, unsigned long crc2, unsigned long len2)
{
int n;
unsigned long row;
unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
unsigned long 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
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
#elif HAVE_SC_NPROCESSORS_ONLN
return sysconf(_SC_NPROCESSORS_ONLN);
#endif
return -1;
}
unsigned int WebUtil::DecodeBase64(char* szInputBuffer, int iInputBufferLength, char* szOutputBuffer)
{
unsigned int InputBufferIndex = 0;
@@ -2578,8 +2369,6 @@ GUnzipStream::EStatus GUnzipStream::Read(const void **pOutputBuffer, int *iOutpu
return zlError;
}
#endif
Tokenizer::Tokenizer(const char* szDataString, const char* szSeparators)
{
// an optimization to avoid memory allocation for short data string (shorten than 1024 chars)
@@ -2634,3 +2423,5 @@ char* Tokenizer::Next()
}
return szToken;
}
#endif

View File

@@ -26,9 +26,13 @@
#ifndef UTIL_H
#define UTIL_H
#ifdef DIRBROWSER_SNAPSHOT
#include <deque>
#ifdef WIN32
#include <stdio.h>
#include <io.h>
#else
#include <dirent.h>
#endif
#include <time.h>
#ifdef WIN32
@@ -45,23 +49,12 @@ private:
HANDLE m_hFile;
bool m_bFirst;
#else
void* m_pDir; // DIR*, declared as void* to avoid including of <dirent>
DIR* m_pDir;
struct dirent* m_pFindData;
#endif
#ifdef DIRBROWSER_SNAPSHOT
bool m_bSnapshot;
typedef std::deque<char*> FileList;
FileList m_Snapshot;
FileList::iterator m_itSnapshot;
#endif
public:
#ifdef DIRBROWSER_SNAPSHOT
DirBrowser(const char* szPath, bool bSnapshot = true);
#else
DirBrowser(const char* szPath);
#endif
~DirBrowser();
const char* Next();
};
@@ -82,11 +75,12 @@ public:
class Util
{
public:
static char* BaseFileName(const char* filename);
static void NormalizePathSeparators(char* szPath);
static bool LoadFileIntoBuffer(const char* szFileName, char** pBuffer, int* pBufferLength);
static bool SaveBufferIntoFile(const char* szFileName, const char* szBuffer, int iBufLen);
static bool CreateSparseFile(const char* szFilename, long long iSize);
static bool CreateSparseFile(const char* szFilename, int iSize);
static bool TruncateFile(const char* szFilename, int iSize);
static void MakeValidFilename(char* szFilename, char cReplaceChar, bool bAllowSlashes);
static bool MakeUniqueFilename(char* szDestBufFilename, int iDestBufSize, const char* szDestDir, const char* szBasename);
@@ -163,18 +157,14 @@ public:
*/
static const char* VersionRevision() { return VersionRevisionBuf; };
static char VersionRevisionBuf[40];
static void InitVersionRevision();
static unsigned long Crc32(unsigned char *block, unsigned long length);
static unsigned long Crc32m(unsigned long startCrc, unsigned char *block, unsigned long length);
static unsigned long Crc32Combine(unsigned long crc1, unsigned long crc2, unsigned long len2);
/*
* Returns number of available CPU cores or -1 if it could not be determined
* Initialize buffer for program version and revision number.
* This function must be called during program initialization before any
* call to "VersionRevision()".
*/
static int NumberOfCpuCores();
static void InitVersionRevision();
static char VersionRevisionBuf[40];
};
class WebUtil

View File

@@ -1,7 +1,7 @@
/*
* This file is part of nzbget
*
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
* Copyright (C) 2007 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
@@ -30,7 +30,6 @@
#include "win32.h"
#include <string.h>
#include <stdio.h>
#include "nzbget.h"
#include "Log.h"

View File

@@ -59,6 +59,9 @@
/* Define to 1 if libpar2 supports cancelling (needs a special patch) */
#define HAVE_PAR2_CANCEL
/* Define to 1 if libpar2 has bugfixes applied (needs a special patch) */
#define HAVE_PAR2_BUGFIXES_V2
/* Define to 1 if function GetAddrInfo is supported */
#define HAVE_GETADDRINFO
@@ -71,7 +74,7 @@
/* Define to 1 if spinlocks are supported */
#define HAVE_SPINLOCK
#define VERSION "14.1"
#define VERSION "13.0"
/* Suppress warnings */
#define _CRT_SECURE_NO_DEPRECATE

View File

@@ -1,3 +0,0 @@
par2cmdline 0.4: Peter Brian Clements <peterbclements@users.sourceforge.net>
library API: Francois Lesueur <flesueur@users.sourceforge.net>
changes for NZBGet: Andrey Prygunkov <hugbug@users.sourceforge.net>

View File

@@ -1,326 +0,0 @@
Based on libpar2 v 0.4 (http://launchpad.net/libpar2), which
is a Debian/Ubuntu fork of original libpar2 (http://parchive.sourceforge.net),
which is a library for par2 based on par2cmdline 0.4.
Changes made to libpar2-0.4:
- removed files not required for NZBGet;
- eliminated dependency from libsigc++ by changing of library
API to use virtual functions instead of sigc++ signals.
par2cmdline README follows :
-------------------------------------------------------------
par2cmdline is a PAR 2.0 compatible file verification and repair tool.
See http://parchive.sourceforge.net for details of PAR 2.0 specification
and discussion of all things PAR.
WHAT EXACTLY IS PAR2CMDLINE?
par2cmdline is a program for creating and using PAR2 files to detect
damage in data files and repair them if necessary. It can be used with
any kind of file.
WHY IS PAR 2.0 better than PAR 1.0?
* It is not necessary to split a single large file into many equally
size small files (although you can still do so if you wish).
* There is no loss of efficiency when operating on multiple files
of different sizes.
* It is possible to repair damaged files (using exactly the amount of
recovery data that corresponds to the amount of damage), rather than
requiring the complete reconstruction of the damaged file.
* Recovery files may be of different sizes making it possible to
obtain exactly the amount of recovery data required to carry out
a repair.
* Because damaged data files are still useable during the recovery
process, less recovery data is required to achieve a successfull
repair. It is not therefore necessary to create as much recovery
data in the first place to achieve the same level of protection.
* You can protect up to 32768 files rather than the 256 that PAR 1.0
is limited to.
* Damaged or incomplete recovery files can also be used during the
recovery process in the same way that damaged data files can.
* You require less recovery data to provide the same level of protection
from damage compared with PAR 1.0.
DOES PAR 2.0 HAVE ANY DISSADVANTAGES?
Yes, there is one dissadvantage:
* All PAR 2.0 program will take somewhat longer to create recovery
files than a PAR 1.0 program does.
This dissadvantage is considerably mitigated by the fact that you don't
need to create as much recovery data in the first place to provide the
same level of protection against loss and damage.
COMPILING PAR2CMDLINE
You should have received par2cmdline in the form of source code which
you can compile on your computer. You may optionally have received a
pre-compiled version of the program for your operating system.
If you have only downloaded a precompiled executable, then the source
code should be available from the same location that you downloaded the
executable from.
If you have MS Visual Studio .NET, then just open the par2cmdline.sln
file and compile. You should then copy par2cmdline.exe to an appropriate
location that is on your path.
To compile on Linux and other unix variants use the following commands:
./configure
make
make check
make install
See INSTALL for full details of how to use the "configure" script.
USING PAR2CMDLINE
The command line parameters for par2cmdline are as follow:
par2 c(reate) [options] <par2 file> [files]
par2 v(erify) [options] <par2 file> [files]
par2 r(epair) [options] <par2 file> [files]
Also:
par2create [options] <par2 file> [files]
par2verify [options] <par2 file> [files]
par2repair [options] <par2 file> [files]
Options:
-b<n> : Set the Block-Count
-s<n> : Set the Block-Size (Don't use both -b and -s)
-r<n> : Level of Redundancy (%)
-c<n> : Recovery block count (don't use both -r and -c)
-f<n> : First Recovery-Block-Number
-u : Uniform recovery file sizes
-l : Limit size of recovery files (Don't use both -u and -l)
-n<n> : Number of recovery files (Don't use both -n and -l)
-m<n> : Memory (in MB) to use
-v [-v]: Be more verbose
-q [-q]: Be more quiet (-qq gives silence)
-- : Treat all remaining CommandLine as filenames
If you wish to create par2 files for a single source file, you may leave
out the name of the par2 file from the command line. par2cmdline will then
assume that you wish to base the filenames for the par2 files on the name
of the source file.
You may also leave off the .par2 file extension when verifying and repairing.
CREATING PAR2 FILES
With PAR 2.0 you can create PAR2 recovery files for as few as 1 or as many as
32768 files. If you wanted to create PAR1 recovery files for a single file
you are forced to split the file into muliple parts and RAR is frequently
used for this purpose. You do NOT need to split files with PAR 2.0.
To create PAR 2 recovery files for a single data file (e.g. one called
test.mpg), you can use the following command:
par2 create test.mpg
If test.mpg is an 800 MB file, then this will create a total of 8 PAR2 files
with the following filenames (taking roughly 6 minutes on a PC with a
1500MHz CPU):
test.mpg.par2 - This is an index file for verification only
test.mpg.vol00+01.par2 - Recovery file with 1 recovery block
test.mpg.vol01+02.par2 - Recovery file with 2 recovery blocks
test.mpg.vol03+04.par2 - Recovery file with 4 recovery blocks
test.mpg.vol07+08.par2 - Recovery file with 8 recovery blocks
test.mpg.vol15+16.par2 - Recovery file with 16 recovery blocks
test.mpg.vol31+32.par2 - Recovery file with 32 recovery blocks
test.mpg.vol63+37.par2 - Recovery file with 37 recovery blocks
The test.mpg.par2 file is 39 KB in size and the other files vary in size from
443 KB to 15 MB.
These par2 files will enable the recovery of up to 100 errors totalling 40 MB
of lost or damaged data from the original test.mpg file when it and the par2
files are posted on UseNet.
When posting on UseNet it is recommended that you use the "-s" option to set
a blocksize that is equal to the Article size that you will use to post the
data file. If you wanted to post the test.mpg file using an article size
of 300 KB then the command you would type is:
par2 create -s307200 test.mpg
This will create 9 PAR2 files instead of 8, and they will be capable of
correcting up to 134 errors totalling 40 MB. It will take roughly 8 minutes
to create the recovery files this time.
In both of these two examples, the total quantity of recovery data created
was 40 MB (which is 5% of 800 MB). If you wish to create a greater or lesser
quantity of recovery data, you can use the "-r" option.
To create 10% recovery data instead of the default of 5% and also to use a
block size of 300 KB, you would use the following command:
par2 create -s307200 -r10 test.mpg
This would also create 9 PAR2 files, but they would be able to correct up to
269 errors totalling 80 MB. Since twice as much recovery data is created, it
will take about 16 minutes to do so with a 1500MHz CPU.
The "-u" and "-n" options can be used to control exactly how many recovery
files are created and how the recovery blocks are distributed amoungst them.
They do not affect the total quantity of recovery data created.
The "-f" option is used when you create additional recovery data.
e.g. If you have already created 10% and want another 5% then you migh use
the following command:
par2 create -s307200 -r5 -f300 test.mpg
This specifies the same block size (which is a requirement for additional
recovery files), 5% recovery data, and a first block number of 300.
The "-m" option controls how much memory par2cmdline uses. It defaults to
16 MB unless you override it.
CREATING PAR2 FILES FOR MULTIPLE DATA FILES
When creating PAR2 recovery files form multiple data files, you must specify
the base filename to use for the par2 files and the names of all of the data
files.
If test.mpg had been split into multiple RAR files, then you could use:
par2 create test.mpg.rar.par2 test.mpg.part*.rar
The files filename "test.mpg.rar.par2" says what you want the par2 files to
be called and "test.mpg.part*.rar" should select all of the RAR files.
VERIFYING AND REPAIRING
When using par2 recovery files to verify or repair the data files from
which they were created, you only need to specify the filename of one
of the par2 files to par2cmdline.
e.g.:
par2 verify test.mpg.par2
This tells par2cmdline to use the information in test.mpg.par2 to verify the
data files.
par2cmdline will automatically search for the other par2 files that were
created and use the information they contain to determine the filenames
of the original data files and then to verify them.
If all of the data files are ok, then par2cmdline will report that repair
will not be required.
If any of the data files are missing or damaged, par2cmdline will report
the details of what it has found. If the recovery files contain enough
recovery blocks to repair the damage, you will be told that repair is
possible. Otherwise you will be told exactly how many recovery blocks
will be required in order to repair.
To carry out a repair use the following command:
par2 repair test.mpg.par2
This tells par2cmdline to verify and if possible repair any damaged or
missing files. If a repair is carried out, then each file which is
repaired will be re-verified to confirm that the repair was successful.
MISSNAMED AND INCOMPLETE DATA FILES
If any of the recovery files or data files have the wrong filename, then
par2cmdline will not automatically find and scan them.
To have par2cmdline scan such files, you must include them on the command
line when attempting to verify or repair.
e.g.:
par2 r test.mpg.par2 other.mpg
This tells par2cmdline to scan the file called other.mpg to see if it
contains any data belonging to the original data files.
If one of the extra files specified in this way is an exact match
for a data file, then the repair process will rename the file so that
it has the correct filename.
Because par2cmdline is designed to be able to find good data within a
damaged file, it can do the same with incomplete files downloaded from
UseNet. If some of the articles for a file are missing, you should still
download the file and save it to disk for par2cmdline to scan. If you
do this then you may find that you can carry out a repair in a situation
where you would not otherwise have sufficient recovery data.
You can have par2cmdline scan all files that are in the current directory
using a command such as:
par2 r test.mpg.par2 *
WHAT TO DO WHEN YOU ARE TOLD YOU NEED MORE RECOVERY BLOCKS
If par2cmdline determines that any of the data files are damaged or
missing and finds that there is insufficient recovery data to effect
a repair, you will be told that you need a certain number of recovery
blocks. You can obtain these by downloading additional recovery files.
In order to make things easy, par2 files have filenames that tell you
exactly how many recovery blocks each one contains.
Assuming that the following command was used to create recovery data:
par2 c -b1000 -r5 test.mpg
Then the recovery files that are created would be called:
test.mpg.par2
test.mpg.vol00+01.par2
test.mpg.vol01+02.par2
test.mpg.vol03+04.par2
test.mpg.vol07+08.par2
test.mpg.vol15+16.par2
test.mpg.vol31+19.par2
The first file in this list does not contain any recovery data, it only
contains information sufficient to verify the data files.
Each of the other files contains a different number of recovery blocks.
The number after the '+' sign is the number of recovery blocks and the
number preceding the '+' sign is the block number of the first recovery
block in that file.
If par2cmdline told you that you needed 10 recovery blocks, then you would
need "test.mpg.vol01+02.par2" and "test.mpg.vol07+08.par". You might of course
choose to fetch "test.mpg.vol15+16.par2" instead (in which case you would have
an extra 6 recovery blocks which would not be used for the repair).
NOTES
This version of par2cmdline does not support recording path information for
files. Whilst you can create recovery files for files from multiple locations,
it will expect all files to be in the current directory when verifying and
repairing. This limitation will be corrected in an update.
REED SOLOMON CODING
PAR2 uses Reed Solomon Coding to perform its calculations. For details of this
coding technique try the following link:
``A Tutorial on Reed-Solomon Coding for Fault-Tolerance in RAID-like Systems''
<http://www.cs.utk.edu/~plank/plank/papers/CS-96-332.html>

View File

@@ -1,827 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
CommandLine::ExtraFile::ExtraFile(void)
: filename()
, filesize(0)
{
}
CommandLine::ExtraFile::ExtraFile(const CommandLine::ExtraFile &other)
: filename(other.filename)
, filesize(other.filesize)
{
}
CommandLine::ExtraFile& CommandLine::ExtraFile::operator=(const CommandLine::ExtraFile &other)
{
filename = other.filename;
filesize = other.filesize;
return *this;
}
CommandLine::ExtraFile::ExtraFile(const string &name, u64 size)
: filename(name)
, filesize(size)
{
}
CommandLine::CommandLine(void)
: operation(opNone)
, version(verUnknown)
, noiselevel(nlUnknown)
, blockcount(0)
, blocksize(0)
, firstblock(0)
, recoveryfilescheme(scUnknown)
, recoveryfilecount(0)
, recoveryblockcount(0)
, recoveryblockcountset(false)
, redundancy(0)
, redundancyset(false)
, parfilename()
, extrafiles()
, totalsourcesize(0)
, largestsourcesize(0)
, memorylimit(0)
{
}
void CommandLine::usage(void)
{
cout <<
"\n"
"Usage:\n"
"\n"
" par2 c(reate) [options] <par2 file> [files] : Create PAR2 files\n"
" par2 v(erify) [options] <par2 file> [files] : Verify files using PAR2 file\n"
" par2 r(epair) [options] <par2 file> [files] : Repair files using PAR2 files\n"
"\n"
"You may also leave out the \"c\", \"v\", and \"r\" commands by using \"parcreate\",\n"
"\"par2verify\", or \"par2repair\" instead.\n"
"\n"
"Options:\n"
"\n"
" -b<n> : Set the Block-Count\n"
" -s<n> : Set the Block-Size (Don't use both -b and -s)\n"
" -r<n> : Level of Redundancy (%%)\n"
" -c<n> : Recovery block count (Don't use both -r and -c)\n"
" -f<n> : First Recovery-Block-Number\n"
" -u : Uniform recovery file sizes\n"
" -l : Limit size of recovery files (Don't use both -u and -l)\n"
" -n<n> : Number of recovery files (Don't use both -n and -l)\n"
" -m<n> : Memory (in MB) to use\n"
" -v [-v]: Be more verbose\n"
" -q [-q]: Be more quiet (-q -q gives silence)\n"
" -- : Treat all remaining CommandLine as filenames\n"
"\n"
"If you wish to create par2 files for a single source file, you may leave\n"
"out the name of the par2 file from the command line.\n";
}
bool CommandLine::Parse(int argc, char *argv[])
{
if (argc<1)
{
return false;
}
// Split the program name into path and filename
string path, name;
DiskFile::SplitFilename(argv[0], path, name);
argc--;
argv++;
// Strip ".exe" from the end
if (name.size() > 4 && 0 == stricmp(".exe", name.substr(name.length()-4).c_str()))
{
name = name.substr(0, name.length()-4);
}
// Check the resulting program name
if (0 == stricmp("par2create", name.c_str()))
{
operation = opCreate;
}
else if (0 == stricmp("par2verify", name.c_str()))
{
operation = opVerify;
}
else if (0 == stricmp("par2repair", name.c_str()))
{
operation = opRepair;
}
// Have we determined what operation we want?
if (operation == opNone)
{
if (argc<2)
{
cerr << "Not enough command line arguments." << endl;
return false;
}
switch (tolower(argv[0][0]))
{
case 'c':
if (argv[0][1] == 0 || 0 == stricmp(argv[0], "create"))
operation = opCreate;
break;
case 'v':
if (argv[0][1] == 0 || 0 == stricmp(argv[0], "verify"))
operation = opVerify;
break;
case 'r':
if (argv[0][1] == 0 || 0 == stricmp(argv[0], "repair"))
operation = opRepair;
break;
}
if (operation == opNone)
{
cerr << "Invalid operation specified: " << argv[0] << endl;
return false;
}
argc--;
argv++;
}
bool options = true;
while (argc>0)
{
if (argv[0][0])
{
if (options && argv[0][0] != '-')
options = false;
if (options)
{
switch (tolower(argv[0][1]))
{
case 'b': // Set the block count
{
if (operation != opCreate)
{
cerr << "Cannot specify block count unless creating." << endl;
return false;
}
if (blockcount > 0)
{
cerr << "Cannot specify block count twice." << endl;
return false;
}
else if (blocksize > 0)
{
cerr << "Cannot specify both block count and block size." << endl;
return false;
}
char *p = &argv[0][2];
while (blockcount <= 3276 && *p && isdigit(*p))
{
blockcount = blockcount * 10 + (*p - '0');
p++;
}
if (0 == blockcount || blockcount > 32768 || *p)
{
cerr << "Invalid block count option: " << argv[0] << endl;
return false;
}
}
break;
case 's': // Set the block size
{
if (operation != opCreate)
{
cerr << "Cannot specify block size unless creating." << endl;
return false;
}
if (blocksize > 0)
{
cerr << "Cannot specify block size twice." << endl;
return false;
}
else if (blockcount > 0)
{
cerr << "Cannot specify both block count and block size." << endl;
return false;
}
char *p = &argv[0][2];
while (blocksize <= 429496729 && *p && isdigit(*p))
{
blocksize = blocksize * 10 + (*p - '0');
p++;
}
if (*p || blocksize == 0)
{
cerr << "Invalid block size option: " << argv[0] << endl;
return false;
}
if (blocksize & 3)
{
cerr << "Block size must be a multiple of 4." << endl;
return false;
}
}
break;
case 'r': // Set the amount of redundancy required
{
if (operation != opCreate)
{
cerr << "Cannot specify redundancy unless creating." << endl;
return false;
}
if (redundancyset)
{
cerr << "Cannot specify redundancy twice." << endl;
return false;
}
else if (recoveryblockcountset)
{
cerr << "Cannot specify both redundancy and recovery block count." << endl;
return false;
}
char *p = &argv[0][2];
while (redundancy <= 10 && *p && isdigit(*p))
{
redundancy = redundancy * 10 + (*p - '0');
p++;
}
if (redundancy > 100 || *p)
{
cerr << "Invalid redundancy option: " << argv[0] << endl;
return false;
}
if (redundancy == 0 && recoveryfilecount > 0)
{
cerr << "Cannot set redundancy to 0 and file count > 0" << endl;
return false;
}
redundancyset = true;
}
break;
case 'c': // Set the number of recovery blocks to create
{
if (operation != opCreate)
{
cerr << "Cannot specify recovery block count unless creating." << endl;
return false;
}
if (recoveryblockcountset)
{
cerr << "Cannot specify recovery block count twice." << endl;
return false;
}
else if (redundancyset)
{
cerr << "Cannot specify both recovery block count and redundancy." << endl;
return false;
}
char *p = &argv[0][2];
while (recoveryblockcount <= 32768 && *p && isdigit(*p))
{
recoveryblockcount = recoveryblockcount * 10 + (*p - '0');
p++;
}
if (recoveryblockcount > 32768 || *p)
{
cerr << "Invalid recoveryblockcount option: " << argv[0] << endl;
return false;
}
if (recoveryblockcount == 0 && recoveryfilecount > 0)
{
cerr << "Cannot set recoveryblockcount to 0 and file count > 0" << endl;
return false;
}
recoveryblockcountset = true;
}
break;
case 'f': // Specify the First block recovery number
{
if (operation != opCreate)
{
cerr << "Cannot specify first block number unless creating." << endl;
return false;
}
if (firstblock > 0)
{
cerr << "Cannot specify first block twice." << endl;
return false;
}
char *p = &argv[0][2];
while (firstblock <= 3276 && *p && isdigit(*p))
{
firstblock = firstblock * 10 + (*p - '0');
p++;
}
if (firstblock > 32768 || *p)
{
cerr << "Invalid first block option: " << argv[0] << endl;
return false;
}
}
break;
case 'u': // Specify uniformly sized recovery files
{
if (operation != opCreate)
{
cerr << "Cannot specify uniform files unless creating." << endl;
return false;
}
if (argv[0][2])
{
cerr << "Invalid option: " << argv[0] << endl;
return false;
}
if (recoveryfilescheme != scUnknown)
{
cerr << "Cannot specify two recovery file size schemes." << endl;
return false;
}
recoveryfilescheme = scUniform;
}
break;
case 'l': // Limit the size of the recovery files
{
if (operation != opCreate)
{
cerr << "Cannot specify limit files unless creating." << endl;
return false;
}
if (argv[0][2])
{
cerr << "Invalid option: " << argv[0] << endl;
return false;
}
if (recoveryfilescheme != scUnknown)
{
cerr << "Cannot specify two recovery file size schemes." << endl;
return false;
}
if (recoveryfilecount > 0)
{
cerr << "Cannot specify limited size and number of files at the same time." << endl;
return false;
}
recoveryfilescheme = scLimited;
}
break;
case 'n': // Specify the number of recovery files
{
if (operation != opCreate)
{
cerr << "Cannot specify recovery file count unless creating." << endl;
return false;
}
if (recoveryfilecount > 0)
{
cerr << "Cannot specify recovery file count twice." << endl;
return false;
}
if (redundancyset && redundancy == 0)
{
cerr << "Cannot set file count when redundancy is set to 0." << endl;
return false;
}
if (recoveryblockcountset && recoveryblockcount == 0)
{
cerr << "Cannot set file count when recovery block count is set to 0." << endl;
return false;
}
if (recoveryfilescheme == scLimited)
{
cerr << "Cannot specify limited size and number of files at the same time." << endl;
return false;
}
char *p = &argv[0][2];
while (*p && isdigit(*p))
{
recoveryfilecount = recoveryfilecount * 10 + (*p - '0');
p++;
}
if (recoveryfilecount == 0 || *p)
{
cerr << "Invalid recovery file count option: " << argv[0] << endl;
return false;
}
}
break;
case 'm': // Specify how much memory to use for output buffers
{
if (memorylimit > 0)
{
cerr << "Cannot specify memory limit twice." << endl;
return false;
}
char *p = &argv[0][2];
while (*p && isdigit(*p))
{
memorylimit = memorylimit * 10 + (*p - '0');
p++;
}
if (memorylimit == 0 || *p)
{
cerr << "Invalid memory limit option: " << argv[0] << endl;
return false;
}
}
break;
case 'v':
{
switch (noiselevel)
{
case nlUnknown:
{
if (argv[0][2] == 'v')
noiselevel = nlDebug;
else
noiselevel = nlNoisy;
}
break;
case nlNoisy:
case nlDebug:
noiselevel = nlDebug;
break;
default:
cerr << "Cannot use both -v and -q." << endl;
return false;
break;
}
}
break;
case 'q':
{
switch (noiselevel)
{
case nlUnknown:
{
if (argv[0][2] == 'q')
noiselevel = nlSilent;
else
noiselevel = nlQuiet;
}
break;
case nlQuiet:
case nlSilent:
noiselevel = nlSilent;
break;
default:
cerr << "Cannot use both -v and -q." << endl;
return false;
break;
}
}
break;
case '-':
{
argc--;
argv++;
options = false;
continue;
}
break;
default:
{
cerr << "Invalid option specified: " << argv[0] << endl;
return false;
}
}
}
else
{
list<string> *filenames;
// If the argument includes wildcard characters,
// search the disk for matching files
if (strchr(argv[0], '*') || strchr(argv[0], '?'))
{
string path;
string name;
DiskFile::SplitFilename(argv[0], path, name);
filenames = DiskFile::FindFiles(path, name);
}
else
{
//start of shell expanded * patch. -- Michael Evans
//The shell might expaned * so, if we have our name and we're creating, then filter for files...
if ((parfilename.length() != 0) && (operation == opCreate))
{
#ifdef WIN32
if (GetFileAttributes(argv[0]) & FILE_ATTRIBUTE_DIRECTORY) // != 0, but no need...
#else //Not WIN32, probably *nix
struct stat st;
if (!(stat(argv[0], &st) == 0 && S_ISREG(st.st_mode)))
#endif
{
cerr << "Skipping non-regular file: " << argv[0] << endl;
argc--;
argv++;
options = false;
continue;
}
}//end of shell expanded * patch. -- Michael Evans
filenames = new list<string>;
filenames->push_back(argv[0]);
}
list<string>::iterator fn = filenames->begin();
while (fn != filenames->end())
{
// Convert filename from command line into a full path + filename
string filename = DiskFile::GetCanonicalPathname(*fn);
// If this is the first file on the command line, then it
// is the main PAR2 file.
if (parfilename.length() == 0)
{
// If we are verifying or repairing, the PAR2 file must
// already exist
if (operation != opCreate)
{
// Find the last '.' in the filename
string::size_type where = filename.find_last_of('.');
if (where != string::npos)
{
// Get what follows the last '.'
string tail = filename.substr(where+1);
if (0 == stricmp(tail.c_str(), "par2"))
{
parfilename = filename;
version = verPar2;
}
else if (0 == stricmp(tail.c_str(), "par") ||
(tail.size() == 3 &&
tolower(tail[0]) == 'p' &&
isdigit(tail[1]) &&
isdigit(tail[2])))
{
parfilename = filename;
version = verPar1;
}
}
// If we haven't figured out which version of PAR file we
// are using from the file extension, then presumable the
// files filename was actually the name of a data file.
if (version == verUnknown)
{
// Check for the existence of a PAR2 of PAR file.
if (DiskFile::FileExists(filename + ".par2"))
{
version = verPar2;
parfilename = filename + ".par2";
}
else if (DiskFile::FileExists(filename + ".PAR2"))
{
version = verPar2;
parfilename = filename + ".PAR2";
}
else if (DiskFile::FileExists(filename + ".par"))
{
version = verPar1;
parfilename = filename + ".par";
}
else if (DiskFile::FileExists(filename + ".PAR"))
{
version = verPar1;
parfilename = filename + ".PAR";
}
}
else
{
// Does the specified PAR or PAR2 file exist
if (!DiskFile::FileExists(filename))
{
version = verUnknown;
}
}
if (version == verUnknown)
{
cerr << "The recovery file does not exist: " << filename << endl;
return false;
}
}
else
{
// We are creating a new file
version = verPar2;
parfilename = filename;
}
}
else
{
// All other files must exist
if (!DiskFile::FileExists(filename))
{
cerr << "The source file does not exist: " << filename << endl;
return false;
}
u64 filesize = DiskFile::GetFileSize(filename);
// Ignore all 0 byte files
if (filesize > 0)
{
extrafiles.push_back(ExtraFile(filename, filesize));
// track the total size of the source files and how
// big the largest one is.
totalsourcesize += filesize;
if (largestsourcesize < filesize)
largestsourcesize = filesize;
}
else
{
cout << "Skipping 0 byte file: " << filename << endl;
}
}
++fn;
}
delete filenames;
}
}
argc--;
argv++;
}
if (parfilename.length() == 0)
{
cerr << "You must specify a Recovery file." << endl;
return false;
}
// Default noise level
if (noiselevel == nlUnknown)
{
noiselevel = nlNormal;
}
// If we a creating, check the other parameters
if (operation == opCreate)
{
// If no recovery file size scheme is specified then use Variable
if (recoveryfilescheme == scUnknown)
{
recoveryfilescheme = scVariable;
}
// If neither block count not block size is specified
if (blockcount == 0 && blocksize == 0)
{
// Use a block count of 2000
blockcount = 2000;
}
// If we are creating, the source files must be given.
if (extrafiles.size() == 0)
{
// Does the par filename include the ".par2" on the end?
if (parfilename.length() > 5 && 0 == stricmp(parfilename.substr(parfilename.length()-5, 5).c_str(), ".par2"))
{
// Yes it does.
cerr << "You must specify a list of files when creating." << endl;
return false;
}
else
{
// No it does not.
// In that case check to see if the file exists, and if it does
// assume that you wish to create par2 files for it.
u64 filesize = 0;
if (DiskFile::FileExists(parfilename) &&
(filesize = DiskFile::GetFileSize(parfilename)) > 0)
{
extrafiles.push_back(ExtraFile(parfilename, filesize));
// track the total size of the source files and how
// big the largest one is.
totalsourcesize += filesize;
if (largestsourcesize < filesize)
largestsourcesize = filesize;
}
else
{
// The file does not exist or it is empty.
cerr << "You must specify a list of files when creating." << endl;
return false;
}
}
}
// Strip the ".par2" from the end of the filename of the main PAR2 file.
if (parfilename.length() > 5 && 0 == stricmp(parfilename.substr(parfilename.length()-5, 5).c_str(), ".par2"))
{
parfilename = parfilename.substr(0, parfilename.length()-5);
}
// Assume a redundancy of 5% if neither redundancy or recoveryblockcount were set.
if (!redundancyset && !recoveryblockcountset)
{
redundancy = 5;
}
}
// Assume a memory limit of 16MB if not specified.
if (memorylimit == 0)
{
#ifdef WIN32
u64 TotalPhysicalMemory = 0;
HMODULE hLib = ::LoadLibraryA("kernel32.dll");
if (NULL != hLib)
{
BOOL (WINAPI *pfn)(LPMEMORYSTATUSEX) = (BOOL (WINAPI*)(LPMEMORYSTATUSEX))::GetProcAddress(hLib, "GlobalMemoryStatusEx");
if (NULL != pfn)
{
MEMORYSTATUSEX mse;
mse.dwLength = sizeof(mse);
if (pfn(&mse))
{
TotalPhysicalMemory = mse.ullTotalPhys;
}
}
::FreeLibrary(hLib);
}
if (TotalPhysicalMemory == 0)
{
MEMORYSTATUS ms;
::ZeroMemory(&ms, sizeof(ms));
::GlobalMemoryStatus(&ms);
TotalPhysicalMemory = ms.dwTotalPhys;
}
if (TotalPhysicalMemory == 0)
{
// Assume 128MB
TotalPhysicalMemory = 128 * 1048576;
}
// Half of total physical memory
memorylimit = (size_t)(TotalPhysicalMemory / 1048576 / 2);
#else
memorylimit = 16;
#endif
}
memorylimit *= 1048576;
return true;
}

View File

@@ -1,157 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __COMMANDLINE_H__
#define __COMMANDLINE_H__
// The CommandLine object is responsible for understanding the format
// of the command line parameters are parsing the command line to
// extract details as to what the user wants to do.
class CommandLine
{
public:
CommandLine(void);
// Parse the supplied command line arguments.
bool Parse(int argc, char *argv[]);
// Display details of the correct format for command line parameters.
static void usage(void);
// What operation will we be carrying out
typedef enum
{
opNone = 0,
opCreate, // Create new PAR2 recovery volumes
opVerify, // Verify but don't repair damaged data files
opRepair // Verify and if possible repair damaged data files
} Operation;
typedef enum
{
verUnknown = 0,
verPar1, // Processing PAR 1.0 files
verPar2 // Processing PAR 2.0 files
} Version;
typedef enum
{
scUnknown = 0,
scVariable, // Each PAR2 file will have 2x as many blocks as previous
scLimited, // Limit PAR2 file size
scUniform // All PAR2 files the same size
} Scheme;
typedef enum
{
nlUnknown = 0,
nlSilent, // Absolutely no output (other than errors)
nlQuiet, // Bare minimum of output
nlNormal, // Normal level of output
nlNoisy, // Lots of output
nlDebug // Extra debugging information
} NoiseLevel;
// Any extra files listed on the command line
class ExtraFile
{
public:
ExtraFile(void);
ExtraFile(const ExtraFile&);
ExtraFile& operator=(const ExtraFile&);
ExtraFile(const string &name, u64 size);
string FileName(void) const {return filename;}
u64 FileSize(void) const {return filesize;}
protected:
string filename;
u64 filesize;
};
public:
// Accessor functions for the command line parameters
CommandLine::Operation GetOperation(void) const {return operation;}
CommandLine::Version GetVersion(void) const {return version;}
u64 GetBlockSize(void) const {return blocksize;}
u32 GetBlockCount(void) const {return blockcount;}
u32 GetRedundancy(void) const {return redundancy;}
u32 GetFirstRecoveryBlock(void) const {return firstblock;}
u32 GetRecoveryFileCount(void) const {return recoveryfilecount;}
u32 GetRecoveryBlockCount(void) const {return recoveryblockcount;}
CommandLine::Scheme GetRecoveryFileScheme(void) const {return recoveryfilescheme;}
size_t GetMemoryLimit(void) const {return memorylimit;}
u64 GetLargestSourceSize(void) const {return largestsourcesize;}
u64 GetTotalSourceSize(void) const {return totalsourcesize;}
CommandLine::NoiseLevel GetNoiseLevel(void) const {return noiselevel;}
string GetParFilename(void) const {return parfilename;}
const list<CommandLine::ExtraFile>& GetExtraFiles(void) const {return extrafiles;}
protected:
Operation operation; // The operation to be carried out.
Version version; // What version files will be processed.
NoiseLevel noiselevel; // How much display output should there be.
u32 blockcount; // How many blocks the source files should
// be virtually split into.
u64 blocksize; // What virtual block size to use.
u32 firstblock; // What the exponent value for the first
// recovery block will be.
Scheme recoveryfilescheme; // How the the size of the recovery files should
// be calculated.
u32 recoveryfilecount; // How many recovery files should be created.
u32 recoveryblockcount; // How many recovery blocks should be created.
bool recoveryblockcountset; // Set if the recoveryblockcount as been specified
u32 redundancy; // What percentage of recovery data should
// be created.
bool redundancyset; // Set if the redundancy has been specified
string parfilename; // The name of the PAR2 file to create, or
// the name of the first PAR2 file to read
// when verifying or repairing.
list<ExtraFile> extrafiles; // The list of other files specified on the
// command line. When creating, this will be
// the source files, and when verifying or
// repairing, this will be additional PAR2
// files or data files to be examined.
u64 totalsourcesize; // Total size of the source files.
u64 largestsourcesize; // Size of the largest source file.
size_t memorylimit; // How much memory is permitted to be used
// for the output buffer when creating
// or repairing.
};
typedef list<CommandLine::ExtraFile>::const_iterator ExtraFileIterator;
#endif // __COMMANDLINE_H__

View File

@@ -1,78 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
// The one and only CCITT CRC32 lookup table
crc32table ccitttable(0xEDB88320L);
// Construct the CRC32 lookup table from the specified polynomial
void GenerateCRC32Table(u32 polynomial, u32 (&table)[256])
{
for (u32 i = 0; i <= 255 ; i++)
{
u32 crc = i;
for (u32 j = 0; j < 8; j++)
{
crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
}
table[i] = crc;
}
}
// Construct a CRC32 lookup table for windowing
void GenerateWindowTable(u64 window, u32 (&target)[256])
{
for (u32 i=0; i<=255; i++)
{
u32 crc = ccitttable.table[i];
for (u64 j=0; j<window; j++)
{
crc = ((crc >> 8) & 0x00ffffffL) ^ ccitttable.table[(u8)crc];
}
target[i] = crc;
}
}
// Construct the mask value to apply to the CRC when windowing
u32 ComputeWindowMask(u64 window)
{
u32 result = ~0;
while (window > 0)
{
result = CRCUpdateChar(result, (char)0);
window--;
}
result ^= ~0;
return result;
}

View File

@@ -1,113 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __CRC_H__
#define __CRC_H__
// These global functions are used to compute the CCITT CRC32 checksum of
// blocks of data.
// The CRC for a block of data may be computed piecemeal be repeatedly
// calling CRCUpdateChar, and CRCUpdateBlock.
// Given the CRC for a block of data in a buffer, CRCSlideChar may be used
// to quickly compute the CRC for the block of data in the buffer that is the
// same size but offset one character later in the buffer.
// Construct the CRC32 lookup table from the specified polynomial
void GenerateCRC32Table(u32 polynomial, u32 (&table)[256]);
// A CRC32 lookup table
struct crc32table
{
crc32table(u32 polynomial)
{
GenerateCRC32Table(polynomial, table);
}
u32 table[256];
};
// The one and only CCITT CRC32 lookup table
extern crc32table ccitttable;
// Update the CRC using one character
inline u32 CRCUpdateChar(u32 crc, u8 ch)
{
return ((crc >> 8) & 0x00ffffffL) ^ ccitttable.table[(u8)crc ^ ch];
}
// Update the CRC using a block of characters in a buffer
inline u32 CRCUpdateBlock(u32 crc, size_t length, const void *buffer)
{
const unsigned char *current = (const unsigned char *)buffer;
while (length-- > 0)
{
crc = ((crc >> 8) & 0x00ffffffL) ^ ccitttable.table[(u8)crc ^ (*current++)];
}
return crc;
}
// Update the CRC using a block of 0s.
inline u32 CRCUpdateBlock(u32 crc, size_t length)
{
while (length-- > 0)
{
crc = ((crc >> 8) & 0x00ffffffL) ^ ccitttable.table[(u8)crc];
}
return crc;
}
// Construct a CRC32 lookup table for windowing
void GenerateWindowTable(u64 window, u32 (&windowtable)[256]);
// Construct the mask value to apply to the CRC when windowing
u32 ComputeWindowMask(u64 window);
// Slide the CRC along a buffer by one character (removing the old and adding the new).
// The new character is added using the main CCITT CRC32 table, and the old character
// is removed using the windowtable.
inline u32 CRCSlideChar(u32 crc, u8 chNew, u8 chOld, const u32 (&windowtable)[256])
{
return ((crc >> 8) & 0x00ffffffL) ^ ccitttable.table[(u8)crc ^ chNew] ^ windowtable[chOld];
}
/*
char *buffer;
u64 window;
//...
u32 windowtable[256];
GenerateWindowTable(window, windowtable);
u32 windowmask = ComputeWindowMask(window);
u32 crc = ~0 ^ CRCUpdateBlock(~0, window, buffer);
crc = windowmask ^ CRCSlideChar(windowmask ^ crc, buffer[window], buffer[0], windowtable);
assert(crc == ~0 ^ CRCUpdateBlock(~0, window, buffer+1));
*/
#endif // __CRC_H__

View File

@@ -1,85 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
// Construct the creator packet.
// The only external information required to complete construction is
// the set_id_hash (which is normally computed from information in the
// main packet).
bool CreatorPacket::Create(const MD5Hash &setid)
{
string creator = "Created by " PACKAGE " version " VERSION ".";
// Allocate a packet just large enough for creator name
CREATORPACKET *packet = (CREATORPACKET *)AllocatePacket(sizeof(*packet) + (~3 & (3+(u32)creator.size())));
// Fill in the details the we know
packet->header.magic = packet_magic;
packet->header.length = packetlength;
//packet->header.hash; // Compute shortly
packet->header.setid = setid;
packet->header.type = creatorpacket_type;
// Copy the creator description into the packet
memcpy(packet->client, creator.c_str(), creator.size());
// Compute the packet hash
MD5Context packetcontext;
packetcontext.Update(&packet->header.setid, packetlength - offsetof(PACKET_HEADER, setid));
packetcontext.Final(packet->header.hash);
return true;
}
// Load the packet from disk.
bool CreatorPacket::Load(DiskFile *diskfile, u64 offset, PACKET_HEADER &header)
{
// Is the packet long enough
if (header.length <= sizeof(CREATORPACKET))
{
return false;
}
// Is the packet too large (what is the longest reasonable creator description)
if (header.length - sizeof(CREATORPACKET) > 100000)
{
return false;
}
// Allocate the packet (with a little extra so we will have NULLs after the description)
CREATORPACKET *packet = (CREATORPACKET *)AllocatePacket((size_t)header.length, 4);
packet->header = header;
// Load the rest of the packet from disk
return diskfile->Read(offset + sizeof(PACKET_HEADER),
packet->client,
(size_t)packet->header.length - sizeof(PACKET_HEADER));
}

View File

@@ -1,44 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __CREATORPACKET_H__
#define __CREATORPACKET_H__
// The creator packet records details as to which PAR2 client
// created a particular recovery file.
// The PAR 2.0 specification requires the presence of a
// creator packet, but it is not actually needed for the
// verification or recovery of damaged files.
class CreatorPacket : public CriticalPacket
{
public:
// Construct the packet
CreatorPacket(void) {};
~CreatorPacket(void) {};
// Create a creator packet for a specified set id hash value
bool Create(const MD5Hash &set_id_hash);
// Load a creator packet from a specified file
bool Load(DiskFile *diskfile, u64 offset, PACKET_HEADER &header);
};
#endif // __CREATORPACKET_H__

View File

@@ -1,48 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
bool CriticalPacket::WritePacket(DiskFile &diskfile, u64 fileoffset) const
{
assert(&diskfile != 0 && packetdata != 0 && packetlength != 0);
return diskfile.Write(fileoffset, packetdata, packetlength);
}
void CriticalPacket::FinishPacket(const MD5Hash &setid)
{
assert(packetdata != 0 && packetlength >= sizeof(PACKET_HEADER));
PACKET_HEADER *header = (PACKET_HEADER*)packetdata;
header->setid = setid;
MD5Context packetcontext;
packetcontext.Update(&header->setid, packetlength - offsetof(PACKET_HEADER, setid));
packetcontext.Final(header->hash);
}

View File

@@ -1,145 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __CRITICALPACKET_H__
#define __CRITICALPACKET_H__
// Base class for main packet, file verification packet, file description packet
// and creator packet.
// These packets are all small and are held in memory in their entirity
class CriticalPacket
{
public:
CriticalPacket(void);
~CriticalPacket(void);
public:
// Write a copy of the packet to the specified file at the specified offset
bool WritePacket(DiskFile &diskfile, u64 fileoffset) const;
// Obtain the lenght of the packet.
size_t PacketLength(void) const;
// Allocate some memory for the packet (plus some extra padding).
void* AllocatePacket(size_t length, size_t extra = 0);
// Finish a packet (by storing the set_id_hash and then computing the packet_hash).
void FinishPacket(const MD5Hash &set_id_hash);
protected:
u8 *packetdata;
size_t packetlength;
};
inline CriticalPacket::CriticalPacket(void)
{
// There is no data initially
packetdata = 0;
packetlength = 0;
}
inline CriticalPacket::~CriticalPacket(void)
{
// Delete the data for the packet
delete [] packetdata;
}
inline size_t CriticalPacket::PacketLength(void) const
{
return packetlength;
}
inline void* CriticalPacket::AllocatePacket(size_t length, size_t extra)
{
// Hey! We can't allocate the packet twice
assert(packetlength == 0 && packetdata == 0);
// Remember the requested packet length
packetlength = length;
// Allocate and clear the requested packet length plus the extra.
packetdata = new u8[length+extra];
memset(packetdata, 0, length+extra);
return packetdata;
}
// Class used to record the fact that a copy of a particular critical packet
// will be written to a particular file at a specific offset.
class CriticalPacketEntry
{
public:
CriticalPacketEntry(DiskFile *_diskfile,
u64 _offset,
const CriticalPacket *_packet)
: diskfile(_diskfile)
, offset(_offset)
, packet(_packet)
{}
CriticalPacketEntry(void)
: diskfile(0)
, offset(0)
, packet(0)
{}
CriticalPacketEntry(const CriticalPacketEntry &other)
: diskfile(other.diskfile)
, offset(other.offset)
, packet(other.packet)
{}
CriticalPacketEntry& operator=(const CriticalPacketEntry &other)
{
diskfile = other.diskfile;
offset = other.offset;
packet = other.packet;
return *this;
}
public:
// Write the packet to disk.
bool WritePacket(void) const;
// Obtain the length of the packet.
u64 PacketLength(void) const;
protected:
DiskFile *diskfile;
u64 offset;
const CriticalPacket *packet;
};
inline bool CriticalPacketEntry::WritePacket(void) const
{
assert(packet != 0 && diskfile != 0);
// Tell the packet to write itself to disk
return packet->WritePacket(*diskfile, offset);
}
inline u64 CriticalPacketEntry::PacketLength(void) const
{
assert(packet != 0);
// Ask the packet how big it is.
return packet->PacketLength();
}
#endif // __CRITICALPACKET_H__

View File

@@ -1,107 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
// Open the file associated with the data block if is not already open
bool DataBlock::Open(void)
{
if (diskfile == 0)
return false;
if (diskfile->IsOpen())
return true;
return diskfile->Open();
}
// Read some data at a specified position within a data block
// into a buffer in memory
bool DataBlock::ReadData(u64 position, // Position within the block
size_t size, // Size of the memory buffer
void *buffer) // Pointer to memory buffer
{
assert(diskfile != 0);
// Check to see if the position from which data is to be read
// is within the bounds of the data block
if (length > position)
{
// Compute the file offset and how much data to physically read from disk
u64 fileoffset = offset + position;
size_t want = (size_t)min((u64)size, length - position);
// Read the data from the file into the buffer
if (!diskfile->Read(fileoffset, buffer, want))
return false;
// If the read extends beyond the end of the data block,
// then the rest of the buffer is zeroed.
if (want < size)
{
memset(&((u8*)buffer)[want], 0, size-want);
}
}
else
{
// Zero the whole buffer
memset(buffer, 0, size);
}
return true;
}
// Write some data at a specified position within a datablock
// from memory to disk
bool DataBlock::WriteData(u64 position, // Position within the block
size_t size, // Size of the memory buffer
const void *buffer, // Pointer to memory buffer
size_t &wrote) // Amount actually written
{
assert(diskfile != 0);
wrote = 0;
// Check to see if the position from which data is to be written
// is within the bounds of the data block
if (length > position)
{
// Compute the file offset and how much data to physically write to disk
u64 fileoffset = offset + position;
size_t have = (size_t)min((u64)size, length - position);
// Write the data from the buffer to disk
if (!diskfile->Write(fileoffset, buffer, have))
return false;
wrote = have;
}
return true;
}

View File

@@ -1,133 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __DATABLOCK_H__
#define __DATABLOCK_H__
class DiskFile;
// A Data Block is a block of data of a specific length at a specific
// offset in a specific file.
// It may be either a block of data in a source file from which recovery
// data is being computed, a block of recovery data in a recovery file, or
// a block in a target file that is being reconstructed.
class DataBlock
{
public:
DataBlock(void);
~DataBlock(void);
public:
// Set the length of the block
void SetLength(u64 length);
// Set the location of the block
void SetLocation(DiskFile *diskfile, u64 offset);
void ClearLocation(void);
public:
// Check to see if the location of the block has been set
bool IsSet(void) const;
// Which disk file is this data block in
DiskFile* GetDiskFile(void) const;
// What offset is the block located at
u64 GetOffset(void) const;
// What is the length of this block
u64 GetLength(void) const;
public:
// Open the disk file if it is not already open (so that it can be read)
bool Open(void);
// Read some of the data from disk into memory.
bool ReadData(u64 position, size_t size, void *buffer);
// Write some of the data from memory to disk
bool WriteData(u64 position, size_t size, const void *buffer, size_t &wrote);
protected:
DiskFile *diskfile; // Which disk file is the block associated with
u64 offset; // What is the file offset
u64 length; // How large is the block
};
// Construct the data block
inline DataBlock::DataBlock(void)
{
diskfile = 0;
offset = 0;
length = 0;
}
// Destroy the data block
inline DataBlock::~DataBlock(void)
{
}
// Set the length of the block
inline void DataBlock::SetLength(u64 _length)
{
length = _length;
}
// Set the location of the block
inline void DataBlock::SetLocation(DiskFile *_diskfile, u64 _offset)
{
diskfile = _diskfile;
offset = _offset;
}
// Clear the location of the block
inline void DataBlock::ClearLocation(void)
{
diskfile = 0;
offset = 0;
}
// Check to see of the location is known
inline bool DataBlock::IsSet(void) const
{
return (diskfile != 0);
}
// Which disk file is this data block in
inline DiskFile* DataBlock::GetDiskFile(void) const
{
return diskfile;
}
// What offset is the block located at
inline u64 DataBlock::GetOffset(void) const
{
return offset;
}
// What is the length of this block
inline u64 DataBlock::GetLength(void) const
{
return length;
}
#endif // __DATABLOCK_H__

View File

@@ -1,113 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
// Construct the packet and store the filename and size.
bool DescriptionPacket::Create(string filename, u64 filesize)
{
// Allocate some extra bytes for the packet in memory so that strlen() can
// be used on the filename. The extra bytes do not get written to disk.
FILEDESCRIPTIONPACKET *packet = (FILEDESCRIPTIONPACKET *)AllocatePacket(sizeof(*packet) + (~3 & (3 + (u32)filename.size())), 4);
// Store everything that is currently known in the packet.
packet->header.magic = packet_magic;
packet->header.length = packetlength;
//packet->header.hash; // Not known yet
//packet->header.setid; // Not known yet
packet->header.type = filedescriptionpacket_type;
//packet->fileid; // Not known yet
//packet->hashfull; // Not known yet
//packet->hash16k; // Not known yet
packet->length = filesize;
memcpy(packet->name, filename.c_str(), filename.size());
return true;
}
void DescriptionPacket::Hash16k(const MD5Hash &hash)
{
((FILEDESCRIPTIONPACKET *)packetdata)->hash16k = hash;
}
void DescriptionPacket::HashFull(const MD5Hash &hash)
{
((FILEDESCRIPTIONPACKET *)packetdata)->hashfull = hash;
}
void DescriptionPacket::ComputeFileId(void)
{
FILEDESCRIPTIONPACKET *packet = ((FILEDESCRIPTIONPACKET *)packetdata);
// Compute the fileid from the hash, length, and name fields in the packet.
MD5Context context;
context.Update(&packet->hash16k,
sizeof(FILEDESCRIPTIONPACKET)-offsetof(FILEDESCRIPTIONPACKET,hash16k)
+strlen((const char*)packet->name));
context.Final(packet->fileid);
}
// Load a description packet from a specified file
bool DescriptionPacket::Load(DiskFile *diskfile, u64 offset, PACKET_HEADER &header)
{
// Is the packet big enough
if (header.length <= sizeof(FILEDESCRIPTIONPACKET))
{
return false;
}
// Is the packet too large (what is the longest permissible filename)
if (header.length - sizeof(FILEDESCRIPTIONPACKET) > 100000)
{
return false;
}
// Allocate the packet (with a little extra so we will have NULLs after the filename)
FILEDESCRIPTIONPACKET *packet = (FILEDESCRIPTIONPACKET *)AllocatePacket((size_t)header.length, 4);
packet->header = header;
// Read the rest of the packet from disk
if (!diskfile->Read(offset + sizeof(PACKET_HEADER),
&packet->fileid,
(size_t)packet->header.length - sizeof(PACKET_HEADER)))
return false;
// Are the file and 16k hashes consistent
if (packet->length <= 16384 && packet->hash16k != packet->hashfull)
{
return false;
}
return true;
}

View File

@@ -1,105 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __DESCRIPTIONPACKET_H__
#define __DESCRIPTIONPACKET_H__
// The description packet records details about a file (including its name,
// size, and the Hash of both the whole file and the first 16k of the file).
class DescriptionPacket : public CriticalPacket
{
public:
// Construct the packet
DescriptionPacket(void) {};
~DescriptionPacket(void) {};
public:
// Construct the packet and store the filename and size.
bool Create(string _filename, u64 _filesize);
// Store the computed Hash values in the packet.
void Hash16k(const MD5Hash &hash);
void HashFull(const MD5Hash &hash);
// Compute and return the file id hash from information in the packet
void ComputeFileId(void);
const MD5Hash& FileId(void) const;
// Return the size of the file
u64 FileSize(void) const;
public:
// Load a description packet from a specified file
bool Load(DiskFile *diskfile, u64 offset, PACKET_HEADER &header);
// Return the name of the file
string FileName(void) const;
// Get the Hash values from the packet
const MD5Hash& HashFull(void) const;
const MD5Hash& Hash16k(void) const;
};
// Get the file id from the packet
inline const MD5Hash& DescriptionPacket::FileId(void) const
{
assert(packetdata != 0);
return ((const FILEDESCRIPTIONPACKET*)packetdata)->fileid;
}
// Get the size of the file from the packet
inline u64 DescriptionPacket::FileSize(void) const
{
assert(packetdata != 0);
return ((const FILEDESCRIPTIONPACKET*)packetdata)->length;
}
// Get the name of the file from the packet
// NB whilst the file format does not guarantee that the name will have a NULL
// termination character, par2cmdline always allocates a little extra data
// and fills it with NULLs to allow the filename to be directly read out of
// the packet.
inline string DescriptionPacket::FileName(void) const
{
assert(packetdata != 0);
// return (char*)((const FILEDESCRIPTIONPACKET*)packetdata)->name();
return (char*)((const FILEDESCRIPTIONPACKET*)packetdata)->name;
}
// Get the full file hash value from the packet
inline const MD5Hash& DescriptionPacket::HashFull(void) const
{
assert(packetdata != 0);
return ((const FILEDESCRIPTIONPACKET*)packetdata)->hashfull;
}
// The the hash of the first 16k of the file from the packet
inline const MD5Hash& DescriptionPacket::Hash16k(void) const
{
assert(packetdata != 0);
return ((const FILEDESCRIPTIONPACKET*)packetdata)->hash16k;
}
#endif // __DESCRIPTIONPACKET_H__

View File

@@ -1,997 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
#ifdef WIN32
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define OffsetType __int64
#define MaxOffset 0x7fffffffffffffffI64
#define LengthType unsigned int
#define MaxLength 0xffffffffUL
DiskFile::DiskFile(void)
{
filename;
filesize = 0;
offset = 0;
hFile = INVALID_HANDLE_VALUE;
exists = false;
}
DiskFile::~DiskFile(void)
{
if (hFile != INVALID_HANDLE_VALUE)
::CloseHandle(hFile);
}
// Create new file on disk and make sure that there is enough
// space on disk for it.
bool DiskFile::Create(string _filename, u64 _filesize)
{
assert(hFile == INVALID_HANDLE_VALUE);
filename = _filename;
filesize = _filesize;
// Create the file
hFile = ::CreateFileA(_filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
DWORD error = ::GetLastError();
cerr << "Could not create \"" << _filename << "\": " << ErrorMessage(error) << endl;
return false;
}
if (filesize > 0)
{
// Seek to the end of the file
LONG lowoffset = ((LONG*)&filesize)[0];
LONG highoffset = ((LONG*)&filesize)[1];
if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, lowoffset, &highoffset, FILE_BEGIN))
{
DWORD error = ::GetLastError();
cerr << "Could not set size of \"" << _filename << "\": " << ErrorMessage(error) << endl;
::CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
::DeleteFile(_filename.c_str());
return false;
}
// Set the end of the file
if (!::SetEndOfFile(hFile))
{
DWORD error = ::GetLastError();
cerr << "Could not set size of \"" << _filename << "\": " << ErrorMessage(error) << endl;
::CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
::DeleteFile(_filename.c_str());
return false;
}
}
offset = filesize;
exists = true;
return true;
}
// Write some data to disk
bool DiskFile::Write(u64 _offset, const void *buffer, size_t length)
{
assert(hFile != INVALID_HANDLE_VALUE);
if (offset != _offset)
{
LONG lowoffset = ((LONG*)&_offset)[0];
LONG highoffset = ((LONG*)&_offset)[1];
// Seek to the required offset
if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, lowoffset, &highoffset, FILE_BEGIN))
{
DWORD error = ::GetLastError();
cerr << "Could not write " << (u64)length << " bytes to \"" << filename << "\" at offset " << _offset << ": " << ErrorMessage(error) << endl;
return false;
}
offset = _offset;
}
if (length > MaxLength)
{
cerr << "Could not write " << (u64)length << " bytes to \"" << filename << "\" at offset " << _offset << ": " << "Write too long" << endl;
return false;
}
DWORD write = (LengthType)length;
DWORD wrote;
// Write the data
if (!::WriteFile(hFile, buffer, write, &wrote, NULL))
{
DWORD error = ::GetLastError();
cerr << "Could not write " << (u64)length << " bytes to \"" << filename << "\" at offset " << _offset << ": " << ErrorMessage(error) << endl;
return false;
}
offset += length;
if (filesize < offset)
{
filesize = offset;
}
return true;
}
// Open the file
bool DiskFile::Open(string _filename, u64 _filesize)
{
assert(hFile == INVALID_HANDLE_VALUE);
filename = _filename;
filesize = _filesize;
hFile = ::CreateFileA(_filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
DWORD error = ::GetLastError();
switch (error)
{
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
break;
default:
cerr << "Could not open \"" << _filename << "\": " << ErrorMessage(error) << endl;
}
return false;
}
offset = 0;
exists = true;
return true;
}
// Read some data from disk
bool DiskFile::Read(u64 _offset, void *buffer, size_t length)
{
assert(hFile != INVALID_HANDLE_VALUE);
if (offset != _offset)
{
LONG lowoffset = ((LONG*)&_offset)[0];
LONG highoffset = ((LONG*)&_offset)[1];
// Seek to the required offset
if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, lowoffset, &highoffset, FILE_BEGIN))
{
DWORD error = ::GetLastError();
cerr << "Could not read " << (u64)length << " bytes from \"" << filename << "\" at offset " << _offset << ": " << ErrorMessage(error) << endl;
return false;
}
offset = _offset;
}
if (length > MaxLength)
{
cerr << "Could not read " << (u64)length << " bytes from \"" << filename << "\" at offset " << _offset << ": " << "Read too long" << endl;
return false;
}
DWORD want = (LengthType)length;
DWORD got;
// Read the data
if (!::ReadFile(hFile, buffer, want, &got, NULL))
{
DWORD error = ::GetLastError();
cerr << "Could not read " << (u64)length << " bytes from \"" << filename << "\" at offset " << _offset << ": " << ErrorMessage(error) << endl;
return false;
}
offset += length;
return true;
}
void DiskFile::Close(void)
{
if (hFile != INVALID_HANDLE_VALUE)
{
::CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
}
}
string DiskFile::GetCanonicalPathname(string filename)
{
char fullname[MAX_PATH];
char *filepart;
// Resolve a relative path to a full path
int length = ::GetFullPathName(filename.c_str(), sizeof(fullname), fullname, &filepart);
if (length <= 0 || sizeof(fullname) < length)
return filename;
// Make sure the drive letter is upper case.
fullname[0] = toupper(fullname[0]);
// Translate all /'s to \'s
char *current = strchr(fullname, '/');
while (current)
{
*current++ = '\\';
current = strchr(current, '/');
}
// Copy the root directory to the output string
string longname(fullname, 3);
// Start processing at the first path component
current = &fullname[3];
char *limit = &fullname[length];
// Process until we reach the end of the full name
while (current < limit)
{
char *tail;
// Find the next \, or the end of the string
(tail = strchr(current, '\\')) || (tail = limit);
*tail = 0;
// Create a wildcard to search for the path
string wild = longname + current;
WIN32_FIND_DATA finddata;
HANDLE hFind = ::FindFirstFile(wild.c_str(), &finddata);
if (hFind == INVALID_HANDLE_VALUE)
{
// If the component was not found then just copy the rest of the path to the
// output buffer verbatim.
longname += current;
break;
}
::FindClose(hFind);
// Copy the component found to the output
longname += finddata.cFileName;
current = tail + 1;
// If we have not reached the end of the name, add a "\"
if (current < limit)
longname += '\\';
}
return longname;
}
list<string>* DiskFile::FindFiles(string path, string wildcard)
{
list<string> *matches = new list<string>;
wildcard = path + wildcard;
WIN32_FIND_DATA fd;
HANDLE h = ::FindFirstFile(wildcard.c_str(), &fd);
if (h != INVALID_HANDLE_VALUE)
{
do
{
if (0 == (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
matches->push_back(path + fd.cFileName);
}
} while (::FindNextFile(h, &fd));
::FindClose(h);
}
return matches;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#else // !WIN32
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_FSEEKO
# define OffsetType off_t
# define MaxOffset ((off_t)0x7fffffffffffffffULL)
# define fseek fseeko
#else
# if _FILE_OFFSET_BITS == 64
# define OffsetType unsigned long long
# define MaxOffset 0x7fffffffffffffffULL
# else
# define OffsetType long
# define MaxOffset 0x7fffffffUL
# endif
#endif
#define LengthType unsigned int
#define MaxLength 0xffffffffUL
DiskFile::DiskFile(void)
{
//filename;
filesize = 0;
offset = 0;
file = 0;
exists = false;
}
DiskFile::~DiskFile(void)
{
if (file != 0)
fclose(file);
}
// Create new file on disk and make sure that there is enough
// space on disk for it.
bool DiskFile::Create(string _filename, u64 _filesize)
{
assert(file == 0);
filename = _filename;
filesize = _filesize;
file = fopen(_filename.c_str(), "wb");
if (file == 0)
{
cerr << "Could not create: " << _filename << endl;
return false;
}
if (_filesize > (u64)MaxOffset)
{
cerr << "Requested file size for " << _filename << " is too large." << endl;
return false;
}
if (_filesize > 0)
{
if (fseek(file, (OffsetType)_filesize-1, SEEK_SET))
{
fclose(file);
file = 0;
::remove(filename.c_str());
cerr << "Could not set end of file: " << _filename << endl;
return false;
}
if (1 != fwrite(&_filesize, 1, 1, file))
{
fclose(file);
file = 0;
::remove(filename.c_str());
cerr << "Could not set end of file: " << _filename << endl;
return false;
}
}
offset = filesize;
exists = true;
return true;
}
// Write some data to disk
bool DiskFile::Write(u64 _offset, const void *buffer, size_t length)
{
assert(file != 0);
if (offset != _offset)
{
if (_offset > (u64)MaxOffset)
{
cerr << "Could not write " << (u64)length << " bytes to " << filename << " at offset " << _offset << endl;
return false;
}
if (fseek(file, (OffsetType)_offset, SEEK_SET))
{
cerr << "Could not write " << (u64)length << " bytes to " << filename << " at offset " << _offset << endl;
return false;
}
offset = _offset;
}
if (length > MaxLength)
{
cerr << "Could not write " << (u64)length << " bytes to " << filename << " at offset " << _offset << endl;
return false;
}
if (1 != fwrite(buffer, (LengthType)length, 1, file))
{
cerr << "Could not write " << (u64)length << " bytes to " << filename << " at offset " << _offset << endl;
return false;
}
offset += length;
if (filesize < offset)
{
filesize = offset;
}
return true;
}
// Open the file
bool DiskFile::Open(string _filename, u64 _filesize)
{
assert(file == 0);
filename = _filename;
filesize = _filesize;
if (_filesize > (u64)MaxOffset)
{
cerr << "File size for " << _filename << " is too large." << endl;
return false;
}
file = fopen(filename.c_str(), "rb");
if (file == 0)
{
return false;
}
offset = 0;
exists = true;
return true;
}
// Read some data from disk
bool DiskFile::Read(u64 _offset, void *buffer, size_t length)
{
assert(file != 0);
if (offset != _offset)
{
if (_offset > (u64)MaxOffset)
{
cerr << "Could not read " << (u64)length << " bytes from " << filename << " at offset " << _offset << endl;
return false;
}
if (fseek(file, (OffsetType)_offset, SEEK_SET))
{
cerr << "Could not read " << (u64)length << " bytes from " << filename << " at offset " << _offset << endl;
return false;
}
offset = _offset;
}
if (length > MaxLength)
{
cerr << "Could not read " << (u64)length << " bytes from " << filename << " at offset " << _offset << endl;
return false;
}
if (1 != fread(buffer, (LengthType)length, 1, file))
{
cerr << "Could not read " << (u64)length << " bytes from " << filename << " at offset " << _offset << endl;
return false;
}
offset += length;
return true;
}
void DiskFile::Close(void)
{
if (file != 0)
{
fclose(file);
file = 0;
}
}
// Attempt to get the full pathname of the file
string DiskFile::GetCanonicalPathname(string filename)
{
// Is the supplied path already an absolute one
if (filename.size() == 0 || filename[0] == '/')
return filename;
// Get the current directory
char curdir[1000];
if (0 == getcwd(curdir, sizeof(curdir)))
{
return filename;
}
// Allocate a work buffer and copy the resulting full path into it.
char *work = new char[strlen(curdir) + filename.size() + 2];
strcpy(work, curdir);
if (work[strlen(work)-1] != '/')
strcat(work, "/");
strcat(work, filename.c_str());
char *in = work;
char *out = work;
while (*in)
{
if (*in == '/')
{
if (in[1] == '.' && in[2] == '/')
{
// skip the input past /./
in += 2;
}
else if (in[1] == '.' && in[2] == '.' && in[3] == '/')
{
// backtrack the output if /../ was found on the input
in += 3;
if (out > work)
{
do
{
out--;
} while (out > work && *out != '/');
}
}
else
{
*out++ = *in++;
}
}
else
{
*out++ = *in++;
}
}
*out = 0;
string result = work;
delete [] work;
return result;
}
list<string>* DiskFile::FindFiles(string path, string wildcard)
{
list<string> *matches = new list<string>;
string::size_type where;
if ((where = wildcard.find_first_of('*')) != string::npos ||
(where = wildcard.find_first_of('?')) != string::npos)
{
string front = wildcard.substr(0, where);
bool multiple = wildcard[where] == '*';
string back = wildcard.substr(where+1);
DIR *dirp = opendir(path.c_str());
if (dirp != 0)
{
struct dirent *d;
while ((d = readdir(dirp)) != 0)
{
string name = d->d_name;
if (name == "." || name == "..")
continue;
if (multiple)
{
if (name.size() >= wildcard.size() &&
name.substr(0, where) == front &&
name.substr(name.size()-back.size()) == back)
{
matches->push_back(path + name);
}
}
else
{
if (name.size() == wildcard.size())
{
string::const_iterator pw = wildcard.begin();
string::const_iterator pn = name.begin();
while (pw != wildcard.end())
{
if (*pw != '?' && *pw != *pn)
break;
++pw;
++pn;
}
if (pw == wildcard.end())
{
matches->push_back(path + name);
}
}
}
}
closedir(dirp);
}
}
else
{
struct stat st;
string fn = path + wildcard;
if (stat(fn.c_str(), &st) == 0)
{
matches->push_back(path + wildcard);
}
}
return matches;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif
bool DiskFile::Open(void)
{
string _filename = filename;
return Open(_filename);
}
bool DiskFile::Open(string _filename)
{
return Open(_filename, GetFileSize(_filename));
}
// Delete the file
bool DiskFile::Delete(void)
{
#ifdef WIN32
assert(hFile == INVALID_HANDLE_VALUE);
#else
assert(file == 0);
#endif
if (filename.size() > 0 && 0 == unlink(filename.c_str()))
{
return true;
}
else
{
cerr << "Cannot delete " << filename << endl;
return false;
}
}
//string DiskFile::GetPathFromFilename(string filename)
//{
// string::size_type where;
//
// if (string::npos != (where = filename.find_last_of('/')) ||
// string::npos != (where = filename.find_last_of('\\')))
// {
// return filename.substr(0, where+1);
// }
// else
// {
// return "." PATHSEP;
// }
//}
void DiskFile::SplitFilename(string filename, string &path, string &name)
{
string::size_type where;
if (string::npos != (where = filename.find_last_of('/')) ||
string::npos != (where = filename.find_last_of('\\')))
{
path = filename.substr(0, where+1);
name = filename.substr(where+1);
}
else
{
path = "." PATHSEP;
name = filename;
}
}
bool DiskFile::FileExists(string filename)
{
struct stat st;
return ((0 == stat(filename.c_str(), &st)) && (0 != (st.st_mode & S_IFREG)));
}
u64 DiskFile::GetFileSize(string filename)
{
struct stat st;
if ((0 == stat(filename.c_str(), &st)) && (0 != (st.st_mode & S_IFREG)))
{
return st.st_size;
}
else
{
return 0;
}
}
// Take a filename from a PAR2 file and replace any characters
// which would be illegal for a file on disk
string DiskFile::TranslateFilename(string filename)
{
string result;
string::iterator p = filename.begin();
while (p != filename.end())
{
unsigned char ch = *p;
bool ok = true;
#ifdef WIN32
if (ch < 32)
{
ok = false;
}
else
{
switch (ch)
{
case '"':
case '*':
case '/':
case ':':
case '<':
case '>':
case '?':
case '\\':
case '|':
ok = false;
}
}
#else
if (ch < 32)
{
ok = false;
}
else
{
switch (ch)
{
case '/':
ok = false;
}
}
#endif
if (ok)
{
result += ch;
}
else
{
// convert problem characters to hex
result += ((ch >> 4) < 10) ? (ch >> 4) + '0' : (ch >> 4) + 'A'-10;
result += ((ch & 0xf) < 10) ? (ch & 0xf) + '0' : (ch & 0xf) + 'A'-10;
}
++p;
}
return result;
}
bool DiskFile::Rename(void)
{
char newname[_MAX_PATH+1];
u32 index = 0;
struct stat st;
do
{
int length = snprintf(newname, _MAX_PATH, "%s.%d", filename.c_str(), ++index);
if (length < 0 || length >= _MAX_PATH)
{
cerr << filename << " cannot be renamed." << endl;
return false;
}
newname[length] = 0;
} while (stat(newname, &st) == 0);
return Rename(newname);
}
bool DiskFile::Rename(string _filename)
{
#ifdef WIN32
assert(hFile == INVALID_HANDLE_VALUE);
#else
assert(file == 0);
#endif
if (::rename(filename.c_str(), _filename.c_str()) == 0)
{
filename = _filename;
return true;
}
else
{
cerr << filename << " cannot be renamed to " << _filename << endl;
return false;
}
}
#ifdef WIN32
string DiskFile::ErrorMessage(DWORD error)
{
string result;
LPVOID lpMsgBuf;
if (::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf,
0,
NULL))
{
result = (char*)lpMsgBuf;
LocalFree(lpMsgBuf);
}
else
{
char message[40];
_snprintf(message, sizeof(message), "Unknown error code (%d)", error);
result = message;
}
return result;
}
#endif
DiskFileMap::DiskFileMap(void)
{
}
DiskFileMap::~DiskFileMap(void)
{
map<string, DiskFile*>::iterator fi = diskfilemap.begin();
while (fi != diskfilemap.end())
{
delete (*fi).second;
++fi;
}
}
bool DiskFileMap::Insert(DiskFile *diskfile)
{
string filename = diskfile->FileName();
assert(filename.length() != 0);
pair<map<string,DiskFile*>::const_iterator,bool> location = diskfilemap.insert(pair<string,DiskFile*>(filename, diskfile));
return location.second;
}
void DiskFileMap::Remove(DiskFile *diskfile)
{
string filename = diskfile->FileName();
assert(filename.length() != 0);
diskfilemap.erase(filename);
}
DiskFile* DiskFileMap::Find(string filename) const
{
assert(filename.length() != 0);
map<string, DiskFile*>::const_iterator f = diskfilemap.find(filename);
return (f != diskfilemap.end()) ? f->second : 0;
}

View File

@@ -1,125 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __DISKFILE_H__
#define __DISKFILE_H__
// A disk file can be any type of file that par2cmdline needs
// to read or write data from or to.
class DiskFile
{
public:
DiskFile(void);
~DiskFile(void);
// Create a file and set its length
bool Create(string filename, u64 filesize);
// Write some data to the file
bool Write(u64 offset, const void *buffer, size_t length);
// Open the file
bool Open(void);
bool Open(string filename);
bool Open(string filename, u64 filesize);
// Check to see if the file is open
#ifdef WIN32
bool IsOpen(void) const {return hFile != INVALID_HANDLE_VALUE;}
#else
bool IsOpen(void) const {return file != 0;}
#endif
// Read some data from the file
bool Read(u64 offset, void *buffer, size_t length);
// Close the file
void Close(void);
// Get the size of the file
u64 FileSize(void) const {return filesize;}
// Get the name of the file
string FileName(void) const {return filename;}
// Does the file exist
bool Exists(void) const {return exists;}
// Rename the file
bool Rename(void); // Pick a filename automatically
bool Rename(string filename);
// Delete the file
bool Delete(void);
public:
static string GetCanonicalPathname(string filename);
static void SplitFilename(string filename, string &path, string &name);
static string TranslateFilename(string filename);
static bool FileExists(string filename);
static u64 GetFileSize(string filename);
// Search the specified path for files which match the specified wildcard
// and return their names in a list.
static list<string>* FindFiles(string path, string wildcard);
protected:
string filename;
u64 filesize;
// OS file handle
#ifdef WIN32
HANDLE hFile;
#else
FILE *file;
#endif
// Current offset within the file
u64 offset;
// Does the file exist
bool exists;
protected:
#ifdef WIN32
static string ErrorMessage(DWORD error);
#endif
};
// This class keeps track of which DiskFile objects exist
// and which file on disk they are associated with.
// It is used to avoid a file being processed twice.
class DiskFileMap
{
public:
DiskFileMap(void);
~DiskFileMap(void);
bool Insert(DiskFile *diskfile);
void Remove(DiskFile *diskfile);
DiskFile* Find(string filename) const;
protected:
map<string, DiskFile*> diskfilemap; // Map from filename to DiskFile
};
#endif // __DISKFILE_H__

View File

@@ -1,255 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
// Construct the checksummer and allocate buffers
FileCheckSummer::FileCheckSummer(DiskFile *_diskfile,
u64 _blocksize,
const u32 (&_windowtable)[256],
u32 _windowmask)
: diskfile(_diskfile)
, blocksize(_blocksize)
, windowtable(_windowtable)
, windowmask(_windowmask)
{
buffer = new char[(size_t)blocksize*2];
filesize = diskfile->FileSize();
currentoffset = 0;
}
FileCheckSummer::~FileCheckSummer(void)
{
delete [] buffer;
}
// Start reading the file at the beginning
bool FileCheckSummer::Start(void)
{
currentoffset = readoffset = 0;
tailpointer = outpointer = buffer;
inpointer = &buffer[blocksize];
// Fill the buffer with new data
if (!Fill())
return false;
// Compute the checksum for the block
checksum = ~0 ^ CRCUpdateBlock(~0, (size_t)blocksize, buffer);
return true;
}
// Jump ahead
bool FileCheckSummer::Jump(u64 distance)
{
// Are we already at the end of the file
if (currentoffset >= filesize)
return false;
// Special distances
if (distance == 0)
return false;
if (distance == 1)
return Step();
// Not allowed to jump more than one block
assert(distance <= blocksize);
if (distance > blocksize)
distance = blocksize;
// Advance the current offset and check if we have reached the end of the file
currentoffset += distance;
if (currentoffset >= filesize)
{
currentoffset = filesize;
tailpointer = outpointer = buffer;
memset(buffer, 0, (size_t)blocksize);
checksum = 0;
return true;
}
// Move past the data being discarded
outpointer += distance;
assert(outpointer <= tailpointer);
// Is there any data left in the buffer that we are keeping
size_t keep = tailpointer - outpointer;
if (keep > 0)
{
// Move it back to the start of the buffer
memmove(buffer, outpointer, keep);
tailpointer = &buffer[keep];
}
else
{
tailpointer = buffer;
}
outpointer = buffer;
inpointer = &buffer[blocksize];
if (!Fill())
return false;
// Compute the checksum for the block
checksum = ~0 ^ CRCUpdateBlock(~0, (size_t)blocksize, buffer);
return true;
}
// Fill the buffer from disk
bool FileCheckSummer::Fill(void)
{
// Have we already reached the end of the file
if (readoffset >= filesize)
return true;
// How much data can we read into the buffer
size_t want = (size_t)min(filesize-readoffset, (u64)(&buffer[2*blocksize]-tailpointer));
if (want > 0)
{
// Read data
if (!diskfile->Read(readoffset, tailpointer, want))
return false;
UpdateHashes(readoffset, tailpointer, want);
readoffset += want;
tailpointer += want;
}
// Did we fill the buffer
want = &buffer[2*blocksize] - tailpointer;
if (want > 0)
{
// Blank the rest of the buffer
memset(tailpointer, 0, want);
}
return true;
}
// Update the full file hash and the 16k hash using the new data
void FileCheckSummer::UpdateHashes(u64 offset, const void *buffer, size_t length)
{
// Are we already beyond the first 16k
if (offset >= 16384)
{
contextfull.Update(buffer, length);
}
// Would we reach the 16k mark
else if (offset+length >= 16384)
{
// Finish the 16k hash
size_t first = (size_t)(16384-offset);
context16k.Update(buffer, first);
// Continue with the full hash
contextfull = context16k;
// Do we go beyond the 16k mark
if (offset+length > 16384)
{
contextfull.Update(&((const char*)buffer)[first], length-first);
}
}
else
{
context16k.Update(buffer, length);
}
}
// Return the full file hash and the 16k file hash
void FileCheckSummer::GetFileHashes(MD5Hash &hashfull, MD5Hash &hash16k) const
{
// Compute the hash of the first 16k
MD5Context context = context16k;
context.Final(hash16k);
// Is the file smaller than 16k
if (filesize < 16384)
{
// The hashes are the same
hashfull = hash16k;
}
else
{
// Compute the hash of the full file
context = contextfull;
context.Final(hashfull);
}
}
// Compute and return the current hash
MD5Hash FileCheckSummer::Hash(void)
{
MD5Context context;
context.Update(outpointer, (size_t)blocksize);
MD5Hash hash;
context.Final(hash);
return hash;
}
u32 FileCheckSummer::ShortChecksum(u64 blocklength)
{
u32 crc = CRCUpdateBlock(~0, (size_t)blocklength, outpointer);
if (blocksize > blocklength)
{
crc = CRCUpdateBlock(crc, (size_t)(blocksize-blocklength));
}
crc ^= ~0;
return crc;
}
MD5Hash FileCheckSummer::ShortHash(u64 blocklength)
{
MD5Context context;
context.Update(outpointer, (size_t)blocklength);
if (blocksize > blocklength)
{
context.Update((size_t)(blocksize-blocklength));
}
// Get the hash value
MD5Hash hash;
context.Final(hash);
return hash;
}

View File

@@ -1,178 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __FILECHECKSUMMER_H__
#define __FILECHECKSUMMER_H__
// This source file defines the FileCheckSummer object which is used
// when scanning a data file to find blocks of undamaged data.
//
// The object uses a "window" into the data file and slides that window
// along the file computing the CRC of the data in that window as it
// goes. If the computed CRC matches the value for a block of data
// from a target data file, then the MD5 Hash value is also computed
// and compared with the value for that block of data. When a match
// has been confirmed, the object jumps forward to where the next
// block of data is expected to start. Whilst the file is being scanned
// the object also computes the MD5 Hash of the whole file and of
// the first 16k of the file for later tests.
class FileCheckSummer
{
public:
FileCheckSummer(DiskFile *diskfile,
u64 blocksize,
const u32 (&windowtable)[256],
u32 windowmask);
~FileCheckSummer(void);
// Start reading the file at the beginning
bool Start(void);
// Jump ahead the specified distance
bool Jump(u64 distance);
// Step forward one byte
bool Step(void);
// Return the current checksum
u32 Checksum(void) const;
// Compute and return the current hash
MD5Hash Hash(void);
// Compute short values of checksum and hash
u32 ShortChecksum(u64 blocklength);
MD5Hash ShortHash(u64 blocklength);
// Do we have less than a full block of data
bool ShortBlock(void) const;
u64 BlockLength(void) const;
// Return the current file offset
u64 Offset(void) const;
// Return the full file hash and the 16k file hash
void GetFileHashes(MD5Hash &hashfull, MD5Hash &hash16k) const;
// Which disk file is this
const DiskFile* GetDiskFile(void) const {return diskfile;}
protected:
DiskFile *diskfile;
u64 blocksize;
const u32 (&windowtable)[256];
u32 windowmask;
u64 filesize;
u64 currentoffset; // file offset for current window position
char *buffer; // buffer for reading from the file
char *outpointer; // position in buffer of scan window
char *inpointer; // &outpointer[blocksize];
char *tailpointer; // after last valid data in buffer
// File offset for next read
u64 readoffset;
// The current checksum
u32 checksum;
// MD5 hash of whole file and of first 16k
MD5Context contextfull;
MD5Context context16k;
protected:
//void ComputeCurrentCRC(void);
void UpdateHashes(u64 offset, const void *buffer, size_t length);
//// Fill the buffers with more data from disk
bool Fill(void);
};
// Return the current checksum
inline u32 FileCheckSummer::Checksum(void) const
{
return checksum;
}
// Return the current block length
inline u64 FileCheckSummer::BlockLength(void) const
{
return min(blocksize, filesize-currentoffset);
}
// Return whether or not the current block is a short one.
inline bool FileCheckSummer::ShortBlock(void) const
{
return BlockLength() < blocksize;
}
// Return the current file offset
inline u64 FileCheckSummer::Offset(void) const
{
return currentoffset;
}
// Step forward one byte
inline bool FileCheckSummer::Step(void)
{
// Are we already at the end of the file
if (currentoffset >= filesize)
return false;
// Advance the file offset and check to see if
// we have reached the end of the file
if (++currentoffset >= filesize)
{
currentoffset = filesize;
tailpointer = outpointer = buffer;
memset(buffer, 0, (size_t)blocksize);
checksum = 0;
return true;
}
// Get the incoming and outgoing characters
char inch = *inpointer++;
char outch = *outpointer++;
// Update the checksum
checksum = windowmask ^ CRCSlideChar(windowmask ^ checksum, inch, outch, windowtable);
// Can the window slide further
if (outpointer < &buffer[blocksize])
return true;
assert(outpointer == &buffer[blocksize]);
// Copy the data back to the beginning of the buffer
memmove(buffer, outpointer, (size_t)blocksize);
inpointer = outpointer;
outpointer = buffer;
tailpointer -= blocksize;
// Fill the rest of the buffer
return Fill();
}
#endif // __FILECHECKSUMMER_H__

View File

@@ -1,29 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif

View File

@@ -1,338 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __GALOIS_H__
#define __GALOIS_H__
template <const unsigned int bits, const unsigned int generator, typename valuetype> class GaloisTable;
template <const unsigned int bits, const unsigned int generator, typename valuetype> class Galois;
template <class g> class GaloisLongMultiplyTable;
// This source file defines the Galois object for carrying out
// arithmetic in GF(2^16) using the generator 0x1100B.
// Also defined are the GaloisTable object (which contains log and
// anti log tables for use in multiplication and division), and
// the GaloisLongMultiplyTable object (which contains tables for
// carrying out multiplation of 16-bit galois numbers 8 bits at a time).
template <const unsigned int bits, const unsigned int generator, typename valuetype>
class GaloisTable
{
public:
typedef valuetype ValueType;
GaloisTable(void);
enum
{
Bits = bits,
Count = 1<<Bits,
Limit = Count-1,
Generator = generator,
};
ValueType log[Count];
ValueType antilog[Count];
};
template <const unsigned int bits, const unsigned int generator, typename valuetype>
class Galois
{
public:
typedef valuetype ValueType;
// Basic constructors
Galois(void) {};
Galois(ValueType v);
// Copy and assignment
Galois(const Galois &right) {value = right.value;}
Galois& operator = (const Galois &right) { value = right.value; return *this;}
// Addition
Galois operator + (const Galois &right) const { return (value ^ right.value); }
Galois& operator += (const Galois &right) { value ^= right.value; return *this;}
// Subtraction
Galois operator - (const Galois &right) const { return (value ^ right.value); }
Galois& operator -= (const Galois &right) { value ^= right.value; return *this;}
// Multiplication
Galois operator * (const Galois &right) const;
Galois& operator *= (const Galois &right);
// Division
Galois operator / (const Galois &right) const;
Galois& operator /= (const Galois &right);
// Power
Galois pow(unsigned int right) const;
Galois operator ^ (unsigned int right) const;
Galois& operator ^= (unsigned int right);
// Cast to value and value access
operator ValueType(void) const {return value;}
ValueType Value(void) const {return value;}
// Direct log and antilog
ValueType Log(void) const;
ValueType ALog(void) const;
enum
{
Bits = GaloisTable<bits,generator,valuetype>::Bits,
Count = GaloisTable<bits,generator,valuetype>::Count,
Limit = GaloisTable<bits,generator,valuetype>::Limit,
};
protected:
ValueType value;
static GaloisTable<bits,generator,valuetype> table;
};
#ifdef LONGMULTIPLY
template <class g>
class GaloisLongMultiplyTable
{
public:
GaloisLongMultiplyTable(void);
typedef g G;
enum
{
Bytes = ((G::Bits + 7) >> 3),
Count = ((Bytes * (Bytes+1)) / 2),
};
G tables[Count * 256 * 256];
};
#endif
// Construct the log and antilog tables from the generator
template <const unsigned int bits, const unsigned int generator, typename valuetype>
inline GaloisTable<bits,generator,valuetype>::GaloisTable(void)
{
u32 b = 1;
for (u32 l=0; l<Limit; l++)
{
log[b] = (ValueType)l;
antilog[l] = (ValueType)b;
b <<= 1;
if (b & Count) b ^= Generator;
}
log[0] = (ValueType)Limit;
antilog[Limit] = 0;
}
// The one and only galois log/antilog table object
template <const unsigned int bits, const unsigned int generator, typename valuetype>
GaloisTable<bits,generator,valuetype> Galois<bits,generator,valuetype>::table;
template <const unsigned int bits, const unsigned int generator, typename valuetype>
inline Galois<bits,generator,valuetype>::Galois(typename Galois<bits,generator,valuetype>::ValueType v)
{
value = v;
}
template <const unsigned int bits, const unsigned int generator, typename valuetype>
inline Galois<bits,generator,valuetype> Galois<bits,generator,valuetype>::operator * (const Galois<bits,generator,valuetype> &right) const
{
if (value == 0 || right.value == 0) return 0;
unsigned int sum = table.log[value] + table.log[right.value];
if (sum >= Limit)
{
return table.antilog[sum-Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename valuetype>
inline Galois<bits,generator,valuetype>& Galois<bits,generator,valuetype>::operator *= (const Galois<bits,generator,valuetype> &right)
{
if (value == 0 || right.value == 0)
{
value = 0;
}
else
{
unsigned int sum = table.log[value] + table.log[right.value];
if (sum >= Limit)
{
value = table.antilog[sum-Limit];
}
else
{
value = table.antilog[sum];
}
}
return *this;
}
template <const unsigned int bits, const unsigned int generator, typename valuetype>
inline Galois<bits,generator,valuetype> Galois<bits,generator,valuetype>::operator / (const Galois<bits,generator,valuetype> &right) const
{
if (value == 0) return 0;
assert(right.value != 0);
if (right.value == 0) {return 0;} // Division by 0!
int sum = table.log[value] - table.log[right.value];
if (sum < 0)
{
return table.antilog[sum+Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename valuetype>
inline Galois<bits,generator,valuetype>& Galois<bits,generator,valuetype>::operator /= (const Galois<bits,generator,valuetype> &right)
{
if (value == 0) return *this;
assert(right.value != 0);
if (right.value == 0) {return *this;} // Division by 0!
int sum = table.log[value] - table.log[right.value];
if (sum < 0)
{
value = table.antilog[sum+Limit];
}
else
{
value = table.antilog[sum];
}
return *this;
}
template <const unsigned int bits, const unsigned int generator, typename valuetype>
inline Galois<bits,generator,valuetype> Galois<bits,generator,valuetype>::pow(unsigned int right) const
{
if (right == 0) return 1;
if (value == 0) return 0;
unsigned int sum = table.log[value] * right;
sum = (sum >> Bits) + (sum & Limit);
if (sum >= Limit)
{
return table.antilog[sum-Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename valuetype>
inline Galois<bits,generator,valuetype> Galois<bits,generator,valuetype>::operator ^ (unsigned int right) const
{
if (right == 0) return 1;
if (value == 0) return 0;
unsigned int sum = table.log[value] * right;
sum = (sum >> Bits) + (sum & Limit);
if (sum >= Limit)
{
return table.antilog[sum-Limit];
}
else
{
return table.antilog[sum];
}
}
template <const unsigned int bits, const unsigned int generator, typename valuetype>
inline Galois<bits,generator,valuetype>& Galois<bits,generator,valuetype>::operator ^= (unsigned int right)
{
if (right == 1) {value = 1; return *this;}
if (value == 0) return *this;
unsigned int sum = table.log[value] * right;
sum = (sum >> Bits) + (sum & Limit);
if (sum >= Limit)
{
value = table.antilog[sum-Limit];
}
else
{
value = table.antilog[sum];
}
return *this;
}
template <const unsigned int bits, const unsigned int generator, typename valuetype>
inline valuetype Galois<bits,generator,valuetype>::Log(void) const
{
return table.log[value];
}
template <const unsigned int bits, const unsigned int generator, typename valuetype>
inline valuetype Galois<bits,generator,valuetype>::ALog(void) const
{
return table.antilog[value];
}
#ifdef LONGMULTIPLY
template <class g>
inline GaloisLongMultiplyTable<g>::GaloisLongMultiplyTable(void)
{
G *table = tables;
for (unsigned int i=0; i<Bytes; i++)
{
for (unsigned int j=i; j<Bytes; j++)
{
for (unsigned int ii=0; ii<256; ii++)
{
for (unsigned int jj=0; jj<256; jj++)
{
*table++ = G(ii << (8*i)) * G(jj << (8*j));
}
}
}
}
}
#endif
typedef Galois<8,0x11D,u8> Galois8;
typedef Galois<16,0x1100B,u16> Galois16;
#endif // __GALOIS_H__

View File

@@ -1,120 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __LETYPE_H__
#define __LETYPE_H__
#if __BYTE_ORDER == __LITTLE_ENDIAN
typedef u16 leu16;
typedef u32 leu32;
typedef u64 leu64;
#else
struct leu16
{
leu16& operator=(const u16 &other);
operator u16(void) const;
u16 value;
};
inline leu16& leu16::operator=(const u16 &other)
{
((unsigned char*)&value)[0] = (unsigned char)((other >> 0) & 0xff);
((unsigned char*)&value)[1] = (unsigned char)((other >> 8) & 0xff);
return *this;
}
inline leu16::operator u16(void) const
{
return ((unsigned char*)&value)[0] << 0 |
((unsigned char*)&value)[1] << 8;
}
struct leu32
{
leu32& operator=(const u32 &other);
operator u32(void) const;
u32 value;
};
inline leu32& leu32::operator=(const u32 &other)
{
((unsigned char*)&value)[0] = (unsigned char)((other >> 0) & 0xff);
((unsigned char*)&value)[1] = (unsigned char)((other >> 8) & 0xff);
((unsigned char*)&value)[2] = (unsigned char)((other >> 16) & 0xff);
((unsigned char*)&value)[3] = (unsigned char)((other >> 24) & 0xff);
return *this;
}
inline leu32::operator u32(void) const
{
return ((unsigned char*)&value)[0] << 0 |
((unsigned char*)&value)[1] << 8 |
((unsigned char*)&value)[2] << 16 |
((unsigned char*)&value)[3] << 24;
}
struct leu64
{
leu64& operator=(const u64 &other);
operator u64(void) const;
u64 value;
};
inline leu64& leu64::operator=(const u64 &other)
{
((unsigned char*)&value)[0] = (unsigned char)((other >> 0) & 0xff);
((unsigned char*)&value)[1] = (unsigned char)((other >> 8) & 0xff);
((unsigned char*)&value)[2] = (unsigned char)((other >> 16) & 0xff);
((unsigned char*)&value)[3] = (unsigned char)((other >> 24) & 0xff);
((unsigned char*)&value)[4] = (unsigned char)((other >> 32) & 0xff);
((unsigned char*)&value)[5] = (unsigned char)((other >> 40) & 0xff);
((unsigned char*)&value)[6] = (unsigned char)((other >> 48) & 0xff);
((unsigned char*)&value)[7] = (unsigned char)((other >> 56) & 0xff);
return *this;
}
inline leu64::operator u64(void) const
{
return (u64)(((unsigned char*)&value)[0]) << 0 |
(u64)(((unsigned char*)&value)[1]) << 8 |
(u64)(((unsigned char*)&value)[2]) << 16 |
(u64)(((unsigned char*)&value)[3]) << 24 |
(u64)(((unsigned char*)&value)[4]) << 32 |
(u64)(((unsigned char*)&value)[5]) << 40 |
(u64)(((unsigned char*)&value)[6]) << 48 |
(u64)(((unsigned char*)&value)[7]) << 56;
}
#endif
#endif // __LETYPE_H__

View File

@@ -1,130 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
// Construct the main packet from the source files and the block size
bool MainPacket::Create(vector<Par2CreatorSourceFile*> &sourcefiles, u64 _blocksize)
{
recoverablefilecount = totalfilecount =(u32)sourcefiles.size();
blocksize = _blocksize;
// Allocate memory for the main packet with enough fileid entries
MAINPACKET *packet = (MAINPACKET *)AllocatePacket(sizeof(MAINPACKET) + totalfilecount * sizeof(MD5Hash));
// Record the details we already know in the packet
packet->header.magic = packet_magic;
packet->header.length = packetlength;
//packet->header.hash; // Compute shortly
//packet->header.setid; // Compute shortly
packet->header.type = mainpacket_type;
packet->blocksize = _blocksize;
packet->recoverablefilecount = totalfilecount;
//packet->fileid; // Compute shortly
// Sort the source files according to their fileid values
if (totalfilecount > 1)
{
sort(sourcefiles.begin(), sourcefiles.end(), Par2CreatorSourceFile::CompareLess);
}
// Store the fileid values in the main packet
vector<Par2CreatorSourceFile*>::const_iterator sourcefile;
MD5Hash *hash;
for ((sourcefile=sourcefiles.begin()),(hash=packet->fileid);
sourcefile!=sourcefiles.end();
++sourcefile, ++hash)
{
*hash = (*sourcefile)->FileId();
}
// Compute the set_id_hash
MD5Context setidcontext;
setidcontext.Update(&packet->blocksize, packetlength - offsetof(MAINPACKET, blocksize));
setidcontext.Final(packet->header.setid);
// Compute the packet_hash
MD5Context packetcontext;
packetcontext.Update(&packet->header.setid, packetlength - offsetof(MAINPACKET, header.setid));
packetcontext.Final(packet->header.hash);
return true;
}
// Load a main packet from a specified file
bool MainPacket::Load(DiskFile *diskfile, u64 offset, PACKET_HEADER &header)
{
// Is the packet large enough
if (header.length < sizeof(MAINPACKET))
{
return false;
}
// Is there a whole number of fileid values
if (0 < (header.length - sizeof(MAINPACKET)) % sizeof(MD5Hash))
{
return false;
}
// Is the packet too large
if (header.length > sizeof(MAINPACKET) + 32768 * sizeof(MD5Hash))
{
return false;
}
// Compute the total number of entries in the fileid array
totalfilecount = (u32)(((size_t)header.length - sizeof(MAINPACKET)) / sizeof(MD5Hash));
MAINPACKET *packet = (MAINPACKET *)AllocatePacket((size_t)header.length);
packet->header = header;
// Read the rest of the packet from disk
if (!diskfile->Read(offset + sizeof(PACKET_HEADER),
&packet->blocksize,
(size_t)packet->header.length - sizeof(PACKET_HEADER)))
return false;
// Does the packet have enough fileid values
recoverablefilecount = packet->recoverablefilecount;
if (recoverablefilecount > totalfilecount)
{
return false;
}
// Is the block size valid
blocksize = packet->blocksize;
if (blocksize == 0 || (blocksize & 3) != 0)
{
return false;
}
return true;
}

View File

@@ -1,105 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __MAINPACKET_H__
#define __MAINPACKET_H__
// The main packet ties all other critical packets together.
// It specifies the block size to use for both verification of
// files and for the Reed Solomon computation.
// It also specifies how many of the source files are repairable
// and in what order they should be processed.
class MainPacket : public CriticalPacket
{
public:
// Construct the packet
MainPacket(void) {};
~MainPacket(void) {};
public:
// Construct the main packet from the source file list and block size.
// "sourcefiles" will be sorted base on their FileId value.
bool Create(vector<Par2CreatorSourceFile*> &sourcefiles,
u64 _blocksize);
// Load a main packet from a specified file
bool Load(DiskFile *diskfile, u64 offset, PACKET_HEADER &header);
public:
// Get the set id.
const MD5Hash& SetId(void) const;
// Get the block size.
u64 BlockSize(void) const;
// Get the file counts.
u32 RecoverableFileCount(void) const;
u32 TotalFileCount(void) const;
// Get the fileid of one file
const MD5Hash& FileId(u32 filenumber) const;
protected:
u64 blocksize;
u32 totalfilecount;
u32 recoverablefilecount;
};
// Get the data block size
inline u64 MainPacket::BlockSize(void) const
{
assert(packetdata != 0);
return blocksize;
}
// Get the number of recoverable files
inline u32 MainPacket::RecoverableFileCount(void) const
{
assert(packetdata != 0);
return recoverablefilecount;
}
// Get the total number of files
inline u32 MainPacket::TotalFileCount(void) const
{
assert(packetdata != 0);
return totalfilecount;
}
// Get the file id hash of one of the files
inline const MD5Hash& MainPacket::FileId(u32 filenumber) const
{
assert(packetdata != 0);
assert(filenumber<totalfilecount);
// return ((const MAINPACKET*)packetdata)->fileid()[filenumber];
return ((const MAINPACKET*)packetdata)->fileid[filenumber];
}
inline const MD5Hash& MainPacket::SetId(void) const
{
return ((const MAINPACKET*)packetdata)->header.setid;
}
#endif // __MAINPACKET_H__

View File

@@ -1,351 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
// Convert hash values to hex
ostream& operator<<(ostream &result, const MD5Hash &h)
{
char buffer[33];
sprintf(buffer,
"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
h.hash[15], h.hash[14], h.hash[13], h.hash[12],
h.hash[11], h.hash[10], h.hash[9], h.hash[8],
h.hash[7], h.hash[6], h.hash[5], h.hash[4],
h.hash[3], h.hash[2], h.hash[1], h.hash[0]);
return result << buffer;
}
string MD5Hash::print(void) const
{
char buffer[33];
sprintf(buffer,
"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
hash[15], hash[14], hash[13], hash[12],
hash[11], hash[10], hash[9], hash[8],
hash[7], hash[6], hash[5], hash[4],
hash[3], hash[2], hash[1], hash[0]);
return buffer;
}
MD5State::MD5State(void)
{
Reset();
}
// Initialise the 16 byte state
void MD5State::Reset(void)
{
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
}
// Update the state using 64 bytes of new data
void MD5State::UpdateState(const u32 (&block)[16])
{
// Primitive operations
#define F1(x,y,z) ( ((x) & (y)) | ((~(x)) & (z)) )
#define F2(x,y,z) ( ((x) & (z)) | ((~(z)) & (y)) )
#define F3(x,y,z) ( (x) ^ (y) ^ (z) )
#define F4(x,y,z) ( (y) ^ ( (x) | ~(z) ) )
// The first version of ROL does not work on an Alpha CPU!
//#define ROL(x,y) ( ((x) << (y)) | (((unsigned int)x) >> (32-y)) )
#define ROL(x,y) ( ((x) << (y)) | (((x) >> (32-y)) & ((1<<y)-1)))
#define ROUND(f,w,x,y,z,k,s,ti) w = x + ROL(w + f(x,y,z) + block[k] + ti, s)
u32 a = state[0];
u32 b = state[1];
u32 c = state[2];
u32 d = state[3];
ROUND(F1, a, b, c, d, 0, 7, 0xd76aa478);
ROUND(F1, d, a, b, c, 1, 12, 0xe8c7b756);
ROUND(F1, c, d, a, b, 2, 17, 0x242070db);
ROUND(F1, b, c, d, a, 3, 22, 0xc1bdceee);
ROUND(F1, a, b, c, d, 4, 7, 0xf57c0faf);
ROUND(F1, d, a, b, c, 5, 12, 0x4787c62a);
ROUND(F1, c, d, a, b, 6, 17, 0xa8304613);
ROUND(F1, b, c, d, a, 7, 22, 0xfd469501);
ROUND(F1, a, b, c, d, 8, 7, 0x698098d8);
ROUND(F1, d, a, b, c, 9, 12, 0x8b44f7af);
ROUND(F1, c, d, a, b, 10, 17, 0xffff5bb1);
ROUND(F1, b, c, d, a, 11, 22, 0x895cd7be);
ROUND(F1, a, b, c, d, 12, 7, 0x6b901122);
ROUND(F1, d, a, b, c, 13, 12, 0xfd987193);
ROUND(F1, c, d, a, b, 14, 17, 0xa679438e);
ROUND(F1, b, c, d, a, 15, 22, 0x49b40821);
ROUND(F2, a, b, c, d, 1, 5, 0xf61e2562);
ROUND(F2, d, a, b, c, 6, 9, 0xc040b340);
ROUND(F2, c, d, a, b, 11, 14, 0x265e5a51);
ROUND(F2, b, c, d, a, 0, 20, 0xe9b6c7aa);
ROUND(F2, a, b, c, d, 5, 5, 0xd62f105d);
ROUND(F2, d, a, b, c, 10, 9, 0x02441453);
ROUND(F2, c, d, a, b, 15, 14, 0xd8a1e681);
ROUND(F2, b, c, d, a, 4, 20, 0xe7d3fbc8);
ROUND(F2, a, b, c, d, 9, 5, 0x21e1cde6);
ROUND(F2, d, a, b, c, 14, 9, 0xc33707d6);
ROUND(F2, c, d, a, b, 3, 14, 0xf4d50d87);
ROUND(F2, b, c, d, a, 8, 20, 0x455a14ed);
ROUND(F2, a, b, c, d, 13, 5, 0xa9e3e905);
ROUND(F2, d, a, b, c, 2, 9, 0xfcefa3f8);
ROUND(F2, c, d, a, b, 7, 14, 0x676f02d9);
ROUND(F2, b, c, d, a, 12, 20, 0x8d2a4c8a);
ROUND(F3, a, b, c, d, 5, 4, 0xfffa3942);
ROUND(F3, d, a, b, c, 8, 11, 0x8771f681);
ROUND(F3, c, d, a, b, 11, 16, 0x6d9d6122);
ROUND(F3, b, c, d, a, 14, 23, 0xfde5380c);
ROUND(F3, a, b, c, d, 1, 4, 0xa4beea44);
ROUND(F3, d, a, b, c, 4, 11, 0x4bdecfa9);
ROUND(F3, c, d, a, b, 7, 16, 0xf6bb4b60);
ROUND(F3, b, c, d, a, 10, 23, 0xbebfbc70);
ROUND(F3, a, b, c, d, 13, 4, 0x289b7ec6);
ROUND(F3, d, a, b, c, 0, 11, 0xeaa127fa);
ROUND(F3, c, d, a, b, 3, 16, 0xd4ef3085);
ROUND(F3, b, c, d, a, 6, 23, 0x04881d05);
ROUND(F3, a, b, c, d, 9, 4, 0xd9d4d039);
ROUND(F3, d, a, b, c, 12, 11, 0xe6db99e5);
ROUND(F3, c, d, a, b, 15, 16, 0x1fa27cf8);
ROUND(F3, b, c, d, a, 2, 23, 0xc4ac5665);
ROUND(F4, a, b, c, d, 0, 6, 0xf4292244);
ROUND(F4, d, a, b, c, 7, 10, 0x432aff97);
ROUND(F4, c, d, a, b, 14, 15, 0xab9423a7);
ROUND(F4, b, c, d, a, 5, 21, 0xfc93a039);
ROUND(F4, a, b, c, d, 12, 6, 0x655b59c3);
ROUND(F4, d, a, b, c, 3, 10, 0x8f0ccc92);
ROUND(F4, c, d, a, b, 10, 15, 0xffeff47d);
ROUND(F4, b, c, d, a, 1, 21, 0x85845dd1);
ROUND(F4, a, b, c, d, 8, 6, 0x6fa87e4f);
ROUND(F4, d, a, b, c, 15, 10, 0xfe2ce6e0);
ROUND(F4, c, d, a, b, 6, 15, 0xa3014314);
ROUND(F4, b, c, d, a, 13, 21, 0x4e0811a1);
ROUND(F4, a, b, c, d, 4, 6, 0xf7537e82);
ROUND(F4, d, a, b, c, 11, 10, 0xbd3af235);
ROUND(F4, c, d, a, b, 2, 15, 0x2ad7d2bb);
ROUND(F4, b, c, d, a, 9, 21, 0xeb86d391);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
MD5Context::MD5Context(void)
: MD5State()
, used(0)
, bytes(0)
{
}
void MD5Context::Reset(void)
{
MD5State::Reset();
used = 0;
bytes = 0;
}
// Update using 0 bytes
void MD5Context::Update(size_t length)
{
u32 wordblock[16];
memset(wordblock, 0, sizeof(wordblock));
// If there is already some data in the buffer, update
// enough 0 bytes to take us to a whole buffer
if (used > 0)
{
size_t size = min(buffersize-used, length);
Update(wordblock, size);
length -= size;
}
// Update as many whole buffers as possible
while (length >= buffersize)
{
Update(wordblock, buffersize);
length -= buffersize;
}
// Update any remainder
if (length > 0)
{
Update(wordblock, length);
}
}
// Update using data from a buffer
void MD5Context::Update(const void *buffer, size_t length)
{
const unsigned char *current = (const unsigned char *)buffer;
// Update the total amount of data processed.
bytes += length;
// Process any whole blocks
while (used + length >= buffersize)
{
size_t have = buffersize - used;
memcpy(&block[used], current, have);
current += have;
length -= have;
u32 wordblock[16];
for (int i=0; i<16; i++)
{
// Convert source data from little endian format to internal format if different
wordblock[i] = ( ((u32)block[i*4+3]) << 24 ) |
( ((u32)block[i*4+2]) << 16 ) |
( ((u32)block[i*4+1]) << 8 ) |
( ((u32)block[i*4+0]) << 0 );
}
MD5State::UpdateState(wordblock);
used = 0;
}
// Store any remainder
if (length > 0)
{
memcpy(&block[used], current, length);
used += length;
}
}
// Finalise the computation and extract the Hash value
void MD5Context::Final(MD5Hash &output)
{
// Temporary work buffer
u8 buffer[64];
// How many bits were processed
u64 bits = bytes << 3;
// Pad as much as needed so that there are exactly 8 bytes needed to fill the buffer
size_t padding;
if (used >= buffersize-8)
{
padding = buffersize-8 + buffersize - used;
}
else
{
padding = buffersize-8 - used;
}
memset(buffer, 0, padding);
buffer[0] = 0x80;
Update(buffer, padding);
// Pad with an additional 8 bytes containing the bit count in little endian format
buffer[7] = (unsigned char)((bits >> 56) & 0xFF);
buffer[6] = (unsigned char)((bits >> 48) & 0xFF);
buffer[5] = (unsigned char)((bits >> 40) & 0xFF);
buffer[4] = (unsigned char)((bits >> 32) & 0xFF);
buffer[3] = (unsigned char)((bits >> 24) & 0xFF);
buffer[2] = (unsigned char)((bits >> 16) & 0xFF);
buffer[1] = (unsigned char)((bits >> 8) & 0xFF);
buffer[0] = (unsigned char)((bits >> 0) & 0xFF);
Update(buffer, 8);
for (int i = 0; i < 4; i++)
{
// Read out the state and convert it from internal format to little endian format
output.hash[4*i+3] = (u8)((MD5State::state[i] >> 24) & 0xFF);
output.hash[4*i+2] = (u8)((MD5State::state[i] >> 16) & 0xFF);
output.hash[4*i+1] = (u8)((MD5State::state[i] >> 8) & 0xFF);
output.hash[4*i+0] = (u8)((MD5State::state[i] >> 0) & 0xFF);
}
}
// Return the Hash value
MD5Hash MD5Context::Hash(void) const
{
MD5Hash output;
for (unsigned int i = 0; i < 4; i++)
{
// Read out the state and convert it from internal format to little endian format
output.hash[4*i+3] = (unsigned char)((MD5State::state[i] >> 24) & 0xFF);
output.hash[4*i+2] = (unsigned char)((MD5State::state[i] >> 16) & 0xFF);
output.hash[4*i+1] = (unsigned char)((MD5State::state[i] >> 8) & 0xFF);
output.hash[4*i+0] = (unsigned char)((MD5State::state[i] >> 0) & 0xFF);
}
return output;
}
ostream& operator<<(ostream &result, const MD5Context &c)
{
char buffer[50];
sprintf(buffer,
"%08X%08X%08X%08X:%08X%08X",
c.state[3],c.state[2],c.state[1],c.state[0],
(u32)((c.bytes >> 32) & 0xffffffff),
(u32)(c.bytes & 0xffffffff));
return result << buffer;
}
string MD5Context::print(void) const
{
char buffer[50];
sprintf(buffer,
"%08X%08X%08X%08X:%08X%08X",
state[3],state[2],state[1],state[0],
(u32)((bytes >> 32) & 0xffffffff),
(u32)(bytes & 0xffffffff));
return buffer;
}

View File

@@ -1,153 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __MD5_H__
#define __MD5_H__
#ifdef WIN32
#pragma pack(push, 1)
#define PACKED
#else
#define PACKED __attribute__ ((packed))
#endif
// This file defines the MD5Hash and MD5Context objects which are used
// to compute and manipulate the MD5 Hash values for a block of data.
// Usage:
//
// MD5Context context;
// context.Update(buffer, length);
//
// MD5Hash hash;
// context.Final(hash);
// MD5 Hash value
struct MD5Hash;
ostream& operator<<(ostream &s, const MD5Hash &hash);
struct MD5Hash
{
// Comparison operators
bool operator==(const MD5Hash &other) const;
bool operator!=(const MD5Hash &other) const;
bool operator<(const MD5Hash &other) const;
bool operator>=(const MD5Hash &other) const;
bool operator>(const MD5Hash &other) const;
bool operator<=(const MD5Hash &other) const;
// Convert value to hex
friend ostream& operator<<(ostream &s, const MD5Hash &hash);
string print(void) const;
u8 hash[16]; // 16 byte MD5 Hash value
} PACKED;
// Intermediate computation state
class MD5State
{
public:
MD5State(void);
void Reset(void);
public:
void UpdateState(const u32 (&block)[16]);
protected:
u32 state[4]; // 16 byte MD5 computation state
};
// MD5 computation context with 64 byte buffer
class MD5Context : public MD5State
{
public:
MD5Context(void);
~MD5Context(void) {};
void Reset(void);
// Process data from a buffer
void Update(const void *buffer, size_t length);
// Process 0 bytes
void Update(size_t length);
// Compute the final hash value
void Final(MD5Hash &output);
// Get the Hash value and the total number of bytes processed.
MD5Hash Hash(void) const;
u64 Bytes(void) const {return bytes;}
friend ostream& operator<<(ostream &s, const MD5Context &context);
string print(void) const;
protected:
enum {buffersize = 64};
unsigned char block[buffersize];
size_t used;
u64 bytes;
};
// Compare hash values
inline bool MD5Hash::operator==(const MD5Hash &other) const
{
return (0==memcmp(&hash, &other.hash, sizeof(hash)));
}
inline bool MD5Hash::operator!=(const MD5Hash &other) const
{
return !operator==(other);
}
inline bool MD5Hash::operator<(const MD5Hash &other) const
{
size_t index = 15;
while (index > 0 && hash[index] == other.hash[index])
{
index--;
}
return hash[index] < other.hash[index];
}
inline bool MD5Hash::operator>=(const MD5Hash &other) const
{
return !operator<(other);
}
inline bool MD5Hash::operator>(const MD5Hash &other) const
{
return other.operator<(*this);
}
inline bool MD5Hash::operator<=(const MD5Hash &other) const
{
return !other.operator<(*this);
}
#ifdef WIN32
#pragma pack(pop)
#endif
#undef PACKED
#endif // __MD5_H__

View File

@@ -1,301 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __PARCMDLINE_H__
#define __PARCMDLINE_H__
#ifdef WIN32
// Windows includes
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// System includes
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <fcntl.h>
#include <assert.h>
#define snprintf _snprintf
#define stat _stat
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#define __PDP_ENDIAN 3412
#define __BYTE_ORDER __LITTLE_ENDIAN
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef unsigned __int64 u64;
#ifndef _SIZE_T_DEFINED
# ifdef _WIN64
typedef unsigned __int64 size_t;
# else
typedef unsigned int size_t;
# endif
# define _SIZE_T_DEFINED
#endif
#else // WIN32
#ifdef HAVE_CONFIG_H
#include "config.h"
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_STDIO_H
# include <stdio.h>
#endif
#if HAVE_DIRENT_H
# include <dirent.h>
# define NAMELEN(dirent) strlen((dirent)->d_name)
#else
# define dirent direct
# define NAMELEN(dirent) (dirent)->d_namelen
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
#if STDC_HEADERS
# include <string.h>
#else
# if !HAVE_STRCHR
# define strchr index
# define strrchr rindex
# endif
char *strchr(), *strrchr();
# if !HAVE_MEMCPY
# define memcpy(d, s, n) bcopy((s), (d), (n))
# define memove(d, s, n) bcopy((s), (d), (n))
# endif
#endif
#if HAVE_MEMORY_H
# include <memory.h>
#endif
#if !HAVE_STRICMP
# if HAVE_STRCASECMP
# define stricmp strcasecmp
# endif
#endif
#if HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#if HAVE_STDINT_H
# include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#else
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
#endif
#if HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#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
#else // HAVE_CONFIG_H
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <assert.h>
#include <errno.h>
#define _MAX_PATH 255
#define stricmp strcasecmp
#define _stat stat
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
#endif
#endif
#ifdef WIN32
#define PATHSEP "\\"
#define ALTPATHSEP "/"
#else
#define PATHSEP "/"
#define ALTPATHSEP "\\"
#endif
// Return type of par2cmdline
typedef enum Result
{
eSuccess = 0,
eRepairPossible = 1, // Data files are damaged and there is
// enough recovery data available to
// repair them.
eRepairNotPossible = 2, // Data files are damaged and there is
// insufficient recovery data available
// to be able to repair them.
eInvalidCommandLineArguments = 3, // There was something wrong with the
// command line arguments
eInsufficientCriticalData = 4, // The PAR2 files did not contain sufficient
// information about the data files to be able
// to verify them.
eRepairFailed = 5, // Repair completed but the data files
// still appear to be damaged.
eFileIOError = 6, // An error occured when accessing files
eLogicError = 7, // In internal error occurred
eMemoryError = 8, // Out of memory
} Result;
#define LONGMULTIPLY
// STL includes
#include <string>
#include <list>
#include <vector>
#include <map>
#include <algorithm>
#include <ctype.h>
#include <iostream>
#include <iomanip>
#include <cassert>
using namespace std;
#ifdef offsetof
#undef offsetof
#endif
#define offsetof(TYPE, MEMBER) ((size_t) ((char*)(&((TYPE *)1)->MEMBER) - (char*)1))
#include "letype.h"
// par2cmdline includes
#include "galois.h"
#include "crc.h"
#include "md5.h"
#include "par2fileformat.h"
#include "commandline.h"
#include "reedsolomon.h"
#include "diskfile.h"
#include "datablock.h"
#include "criticalpacket.h"
#include "par2creatorsourcefile.h"
#include "mainpacket.h"
#include "creatorpacket.h"
#include "descriptionpacket.h"
#include "verificationpacket.h"
#include "recoverypacket.h"
#include "par2repairersourcefile.h"
#include "filechecksummer.h"
#include "verificationhashtable.h"
//#include "par2creator.h"
#include "par2repairer.h"
//#include "par1fileformat.h"
//#include "par1repairersourcefile.h"
//#include "par1repairer.h"
// Heap checking
#ifdef _MSC_VER
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define DEBUG_NEW new(_NORMAL_BLOCK, THIS_FILE, __LINE__)
#endif
#endif // __PARCMDLINE_H__

View File

@@ -1,342 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
#ifdef _MSC_VER
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif
Par2CreatorSourceFile::Par2CreatorSourceFile(void)
{
descriptionpacket = 0;
verificationpacket = 0;
diskfile = 0;
blockcount = 0;
//diskfilename;
//parfilename;
contextfull = 0;
}
Par2CreatorSourceFile::~Par2CreatorSourceFile(void)
{
delete descriptionpacket;
delete verificationpacket;
delete diskfile;
delete contextfull;
}
// Open the source file, compute the MD5 Hash of the whole file and the first
// 16k of the file, and then compute the FileId and store the results
// in a file description packet and a file verification packet.
bool Par2CreatorSourceFile::Open(CommandLine::NoiseLevel noiselevel, const CommandLine::ExtraFile &extrafile, u64 blocksize, bool deferhashcomputation)
{
// Get the filename and filesize
diskfilename = extrafile.FileName();
filesize = extrafile.FileSize();
// Work out how many blocks the file will be sliced into
blockcount = (u32)((filesize + blocksize-1) / blocksize);
// Determine what filename to record in the PAR2 files
string::size_type where;
if (string::npos != (where = diskfilename.find_last_of('\\')) ||
string::npos != (where = diskfilename.find_last_of('/')))
{
parfilename = diskfilename.substr(where+1);
}
else
{
parfilename = diskfilename;
}
// Create the Description and Verification packets
descriptionpacket = new DescriptionPacket;
descriptionpacket->Create(parfilename, filesize);
verificationpacket = new VerificationPacket;
verificationpacket->Create(blockcount);
// Create the diskfile object
diskfile = new DiskFile;
// Open the source file
if (!diskfile->Open(diskfilename, filesize))
return false;
// Do we want to defer the computation of the full file hash, and
// the block crc and hashes. This is only permitted if there
// is sufficient memory available to create all recovery blocks
// in one pass of the source files (i.e. chunksize == blocksize)
if (deferhashcomputation)
{
// Initialise a buffer to read the first 16k of the source file
size_t buffersize = 16 * 1024;
if (buffersize > filesize)
buffersize = (size_t)filesize;
char *buffer = new char[buffersize];
// Read the data from the file
if (!diskfile->Read(0, buffer, buffersize))
{
diskfile->Close();
delete [] buffer;
return false;
}
// Compute the hash of the data read from the file
MD5Context context;
context.Update(buffer, buffersize);
delete [] buffer;
MD5Hash hash;
context.Final(hash);
// Store the hash in the descriptionpacket and compute the file id
descriptionpacket->Hash16k(hash);
// Compute the fileid and store it in the verification packet.
descriptionpacket->ComputeFileId();
verificationpacket->FileId(descriptionpacket->FileId());
// Allocate an MD5 context for computing the file hash
// during the recovery data generation phase
contextfull = new MD5Context;
}
else
{
// Initialise a buffer to read the source file
size_t buffersize = 1024*1024;
if (buffersize > min(blocksize,filesize))
buffersize = (size_t)min(blocksize,filesize);
char *buffer = new char[buffersize];
// Get ready to start reading source file to compute the hashes and crcs
u64 offset = 0;
u32 blocknumber = 0;
u64 need = blocksize;
MD5Context filecontext;
MD5Context blockcontext;
u32 blockcrc = 0;
// Whilst we have not reached the end of the file
while (offset < filesize)
{
// Work out how much we can read
size_t want = (size_t)min(filesize-offset, (u64)buffersize);
// Read some data from the file into the buffer
if (!diskfile->Read(offset, buffer, want))
{
diskfile->Close();
delete [] buffer;
return false;
}
// If the new data passes the 16k boundary, compute the 16k hash for the file
if (offset < 16384 && offset + want >= 16384)
{
filecontext.Update(buffer, (size_t)(16384-offset));
MD5Context temp = filecontext;
MD5Hash hash;
temp.Final(hash);
// Store the 16k hash in the file description packet
descriptionpacket->Hash16k(hash);
if (offset + want > 16384)
{
filecontext.Update(&buffer[16384-offset], (size_t)(offset+want)-16384);
}
}
else
{
filecontext.Update(buffer, want);
}
// Get ready to update block hashes and crcs
u32 used = 0;
// Whilst we have not used all of the data we just read
while (used < want)
{
// How much of it can we use for the current block
u32 use = (u32)min(need, (u64)(want-used));
blockcrc = ~0 ^ CRCUpdateBlock(~0 ^ blockcrc, use, &buffer[used]);
blockcontext.Update(&buffer[used], use);
used += use;
need -= use;
// Have we finished the current block
if (need == 0)
{
MD5Hash blockhash;
blockcontext.Final(blockhash);
// Store the block hash and block crc in the file verification packet.
verificationpacket->SetBlockHashAndCRC(blocknumber, blockhash, blockcrc);
blocknumber++;
// More blocks
if (blocknumber < blockcount)
{
need = blocksize;
blockcontext.Reset();
blockcrc = 0;
}
}
}
if (noiselevel > CommandLine::nlQuiet)
{
// Display progress
u32 oldfraction = (u32)(1000 * offset / filesize);
offset += want;
u32 newfraction = (u32)(1000 * offset / filesize);
if (oldfraction != newfraction)
{
cout << newfraction/10 << '.' << newfraction%10 << "%\r" << flush;
}
}
}
// Did we finish the last block
if (need > 0)
{
blockcrc = ~0 ^ CRCUpdateBlock(~0 ^ blockcrc, (size_t)need);
blockcontext.Update((size_t)need);
MD5Hash blockhash;
blockcontext.Final(blockhash);
// Store the block hash and block crc in the file verification packet.
verificationpacket->SetBlockHashAndCRC(blocknumber, blockhash, blockcrc);
blocknumber++;
need = 0;
}
// Finish computing the file hash.
MD5Hash filehash;
filecontext.Final(filehash);
// Store the file hash in the file description packet.
descriptionpacket->HashFull(filehash);
// Did we compute the 16k hash.
if (offset < 16384)
{
// Store the 16k hash in the file description packet.
descriptionpacket->Hash16k(filehash);
}
delete [] buffer;
// Compute the fileid and store it in the verification packet.
descriptionpacket->ComputeFileId();
verificationpacket->FileId(descriptionpacket->FileId());
}
return true;
}
void Par2CreatorSourceFile::Close(void)
{
diskfile->Close();
}
void Par2CreatorSourceFile::RecordCriticalPackets(list<CriticalPacket*> &criticalpackets)
{
// Add the file description packet and file verification packet to
// the critical packet list.
criticalpackets.push_back(descriptionpacket);
criticalpackets.push_back(verificationpacket);
}
bool Par2CreatorSourceFile::CompareLess(const Par2CreatorSourceFile* const &left, const Par2CreatorSourceFile* const &right)
{
// Sort source files based on fileid
return left->descriptionpacket->FileId() < right->descriptionpacket->FileId();
}
const MD5Hash& Par2CreatorSourceFile::FileId(void) const
{
// Get the file id hash
return descriptionpacket->FileId();
}
void Par2CreatorSourceFile::InitialiseSourceBlocks(vector<DataBlock>::iterator &sourceblock, u64 blocksize)
{
for (u32 blocknum=0; blocknum<blockcount; blocknum++)
{
// Configure each source block to an appropriate offset and length within the source file.
sourceblock->SetLocation(diskfile, // file
blocknum * blocksize); // offset
sourceblock->SetLength(min(blocksize, filesize - (u64)blocknum * blocksize)); // length
sourceblock++;
}
}
void Par2CreatorSourceFile::UpdateHashes(u32 blocknumber, const void *buffer, size_t length)
{
// Compute the crc and hash of the data
u32 blockcrc = ~0 ^ CRCUpdateBlock(~0, length, buffer);
MD5Context blockcontext;
blockcontext.Update(buffer, length);
MD5Hash blockhash;
blockcontext.Final(blockhash);
// Store the results in the verification packet
verificationpacket->SetBlockHashAndCRC(blocknumber, blockhash, blockcrc);
// Update the full file hash, but don't go beyond the end of the file
if (length > filesize - blocknumber * length)
{
length = (size_t)(filesize - blocknumber * (u64)length);
}
assert(contextfull != 0);
contextfull->Update(buffer, length);
}
void Par2CreatorSourceFile::FinishHashes(void)
{
assert(contextfull != 0);
// Finish computation of the full file hash
MD5Hash hash;
contextfull->Final(hash);
// Store it in the description packet
descriptionpacket->HashFull(hash);
}

View File

@@ -1,81 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __PAR2CREATORSOURCEFILE_H__
#define __PAR2CREATORSOURCEFILE_H__
class DescriptionPacket;
class VerificationPacket;
class DiskFile;
// The Par2CreatorSourceFile contains the file verification and file description
// packet for one source file.
class Par2CreatorSourceFile
{
private:
// Don't permit copying or assignment
Par2CreatorSourceFile(const Par2CreatorSourceFile &other);
Par2CreatorSourceFile& operator=(const Par2CreatorSourceFile &other);
public:
Par2CreatorSourceFile(void);
~Par2CreatorSourceFile(void);
// Open the source file and compute the Hashes and CRCs.
bool Open(CommandLine::NoiseLevel noiselevel, const CommandLine::ExtraFile &extrafile, u64 blocksize, bool deferhashcomputation);
void Close(void);
// Recover the file description and file verification packets
// in the critical packet list.
void RecordCriticalPackets(list<CriticalPacket*> &criticalpackets);
// Get the file id
const MD5Hash& FileId(void) const;
// Sort source files based on the file id hash
static bool CompareLess(const Par2CreatorSourceFile* const &left, const Par2CreatorSourceFile* const &right);
// Allocate the appropriate number of source blocks to the source file
void InitialiseSourceBlocks(vector<DataBlock>::iterator &sourceblock, u64 blocksize);
// Update the file hash and the block crc and hashes
void UpdateHashes(u32 blocknumber, const void *buffer, size_t length);
// Finish computation of the file hash
void FinishHashes(void);
// How many blocks does this source file use
u32 BlockCount(void) const {return blockcount;}
protected:
DescriptionPacket *descriptionpacket; // The file description packet.
VerificationPacket *verificationpacket; // The file verification packet.
DiskFile *diskfile; // The source file
u64 filesize; // The size of the source file.
string diskfilename; // The filename of the source file on disk.
string parfilename; // The filename that will be recorded in the file description packet.
u32 blockcount; // How many blocks the file will be divided into.
MD5Context *contextfull; // MD5 context used to calculate the hash of the whole file
};
#endif // __PAR2CREATORSOURCEFILE_H__

View File

@@ -1,28 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#include "par2cmdline.h"
MAGIC packet_magic = {{'P', 'A', 'R', '2', '\0','P', 'K', 'T'}};
PACKETTYPE fileverificationpacket_type = {{'P', 'A', 'R', ' ', '2', '.', '0', '\0', 'I', 'F', 'S', 'C', '\0','\0','\0','\0'}};
PACKETTYPE filedescriptionpacket_type = {{'P', 'A', 'R', ' ', '2', '.', '0', '\0', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c' }};
PACKETTYPE mainpacket_type = {{'P', 'A', 'R', ' ', '2', '.', '0', '\0', 'M', 'a', 'i', 'n', '\0','\0','\0','\0'}};
PACKETTYPE recoveryblockpacket_type = {{'P', 'A', 'R', ' ', '2', '.', '0', '\0', 'R', 'e', 'c', 'v', 'S', 'l', 'i', 'c' }};
PACKETTYPE creatorpacket_type = {{'P', 'A', 'R', ' ', '2', '.', '0', '\0', 'C', 'r', 'e', 'a', 't', 'o', 'r', '\0'}};

View File

@@ -1,199 +0,0 @@
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline 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.
//
// par2cmdline 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
#ifndef __PAR2FILEFORMAT_H__
#define __PAR2FILEFORMAT_H__
// This file defines the format of a PAR2 file.
// PAR2 files consist of one or more "packets" that contain information
// that is required to be able to verify and repair damaged data files.
// All packets start with a short "header" which contains information
// used to describe what sort of data is stored in the rest of the packet
// and also to allow that data to be verified.
// This file details the format for the following packet types described
// in the PAR 2.0 specification:
// Main Packet struct MAINPACKET
// File Description Packet struct FILEDESCRIPTIONPACKET
// Input File Slice Checksum Packet struct FILEVERIFICATIONPACKET
// Recovery Slice Packet struct RECOVERYBLOCKPACKET
// Creator Packet struct CREATORPACKET
#ifdef WIN32
#pragma pack(push, 1)
#define PACKED
#else
#define PACKED __attribute__ ((packed))
#endif
#ifdef _MSC_VER
#pragma warning(disable:4200)
#endif
// All numeric fields in the file format are in LITTLE ENDIAN format.
// The types leu32 and leu64 are defined in letype.h
// Two simple types used in the packet header.
struct MAGIC {u8 magic[8];} PACKED;
struct PACKETTYPE {u8 type[16];} PACKED;
// Every packet starts with a packet header.
struct PACKET_HEADER
{
// Header
MAGIC magic; // = {'P', 'A', 'R', '2', '\0', 'P', 'K', 'T'}
leu64 length; // Length of entire packet including header
MD5Hash hash; // Hash of entire packet excepting the first 3 fields
MD5Hash setid; // Normally computed as the Hash of body of "Main Packet"
PACKETTYPE type; // Used to specify the meaning of the rest of the packet
} PACKED;
// The file verification packet is used to determine whether or not any
// parts of a damaged file are useable.
// It contains a FileId used to pair it with a corresponding file description
// packet, followed by an array of hash and crc values. The number of entries in
// the array can be determined from the packet_length.
struct FILEVERIFICATIONENTRY
{
MD5Hash hash;
leu32 crc;
} PACKED;
struct FILEVERIFICATIONPACKET
{
PACKET_HEADER header;
// Body
MD5Hash fileid; // MD5hash of file_hash_16k, file_length, file_name
FILEVERIFICATIONENTRY entries[];
} PACKED;
// The file description packet is used to record the name of the file,
// its size, and the Hash of both the whole file and the first 16k of
// the file.
// If the name of the file is an exact multiple of 4 characters in length
// then it may not have a NULL termination. If the name of the file is not
// an exact multiple of 4, then it will be padded with 0 bytes at the
// end to make it up to a multiple of 4.
struct FILEDESCRIPTIONPACKET
{
PACKET_HEADER header;
// Body
MD5Hash fileid; // MD5hash of [hash16k, length, name]
MD5Hash hashfull; // MD5 Hash of the whole file
MD5Hash hash16k; // MD5 Hash of the first 16k of the file
leu64 length; // Length of the file
u8 name[]; // Name of the file, padded with 1 to 3 zero bytes to reach
// a multiple of 4 bytes.
// Actual length can be determined from overall packet
// length and then working backwards to find the first non
// zero character.
//u8* name(void) {return (u8*)&this[1];}
//const u8* name(void) const {return (const u8*)&this[1];}
} PACKED;
// The main packet is used to tie together the other packets in a recovery file.
// It specifies the block size used to virtually slice the source files, a count
// of the number of source files, and an array of Hash values used to specify
// in what order the source files are processed.
// Each entry in the fileid array corresponds with the fileid value
// in a file description packet and a file verification packet.
// The fileid array may contain more entries than the count of the number
// of recoverable files. The extra entries correspond to files that were not
// used during the creation of the recovery files and which may not therefore
// be repaired if they are found to be damaged.
struct MAINPACKET
{
PACKET_HEADER header;
// Body
leu64 blocksize;
leu32 recoverablefilecount;
MD5Hash fileid[0];
//MD5Hash* fileid(void) {return (MD5Hash*)&this[1];}
//const MD5Hash* fileid(void) const {return (const MD5Hash*)&this[1];}
} PACKED;
// The creator packet is used to identify which program created a particular
// recovery file. It is not required for verification or recovery of damaged
// files.
struct CREATORPACKET
{
PACKET_HEADER header;
// Body
u8 client[];
//u8* client(void) {return (u8*)&this[1];}
} PACKED;
// The recovery block packet contains a single block of recovery data along
// with the exponent value used during the computation of that block.
struct RECOVERYBLOCKPACKET
{
PACKET_HEADER header;
// Body
leu32 exponent;
// unsigned long data[];
// unsigned long* data(void) {return (unsigned long*)&this[1];}
} PACKED;
#ifdef _MSC_VER
#pragma warning(default:4200)
#endif
#ifdef WIN32
#pragma pack(pop)
#endif
#undef PACKED
// Operators for comparing the MAGIC and PACKETTYPE values
inline bool operator == (const MAGIC &left, const MAGIC &right)
{
return (0==memcmp(&left, &right, sizeof(left)));
}
inline bool operator != (const MAGIC &left, const MAGIC &right)
{
return !operator==(left, right);
}
inline bool operator == (const PACKETTYPE &left, const PACKETTYPE &right)
{
return (0==memcmp(&left, &right, sizeof(left)));
}
inline bool operator != (const PACKETTYPE &left, const PACKETTYPE &right)
{
return !operator==(left, right);
}
extern MAGIC packet_magic;
extern PACKETTYPE fileverificationpacket_type;
extern PACKETTYPE filedescriptionpacket_type;
extern PACKETTYPE mainpacket_type;
extern PACKETTYPE recoveryblockpacket_type;
extern PACKETTYPE creatorpacket_type;
#endif //__PAR2FILEFORMAT_H__

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