mirror of
https://github.com/nzbget/nzbget.git
synced 2026-01-03 19:47:44 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
491fc1456e |
29
AUTHORS
29
AUTHORS
@@ -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)
|
||||
|
||||
62
Makefile.am
62
Makefile.am
@@ -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 {} \;
|
||||
|
||||
|
||||
615
Makefile.in
615
Makefile.in
@@ -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
87
README
@@ -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
|
||||
NZBGet’s 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
|
||||
=====================================
|
||||
|
||||
82
config.h.in
82
config.h.in
@@ -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
|
||||
|
||||
206
configure.ac
206
configure.ac
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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); }
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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)))
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -73,7 +73,6 @@ private:
|
||||
void ResetHangingDownloads();
|
||||
void AdjustDownloadsLimit();
|
||||
void Load();
|
||||
void SavePartialState();
|
||||
|
||||
protected:
|
||||
virtual void LogDebugInfo();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, ...);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
326
lib/par2/README
326
lib/par2/README
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
113
lib/par2/crc.h
113
lib/par2/crc.h
@@ -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__
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
351
lib/par2/md5.cpp
351
lib/par2/md5.cpp
@@ -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;
|
||||
}
|
||||
|
||||
153
lib/par2/md5.h
153
lib/par2/md5.h
@@ -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__
|
||||
@@ -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__
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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'}};
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user