[Box Backup-dev] Bug: Compare stopping on locked files

Ben Summers boxbackup-dev@fluffy.co.uk
Mon, 26 Jun 2006 10:02:14 +0100


Pascal,

Thanks for the patch, which shows the root cause of the problem. I  
think we need to refine it a bit though.

* You don't actually need to understand the contents of the stream  
from the server, merely discarding all the data it contains is  
sufficient.

* Having said that, we should really be testing for readability  
before opening the file and requesting the data from the server in  
the first place.

* And finally, if there are errors, they need to be reported in the  
summary from the compare.

Ben




On 20 Jun 2006, at 22:50, Pascal Lalonde wrote:

> On win32, when using bbackupquery, a compare command fails for a given
> location when it encounters a locked file, which is so common in
> Windows, especially on multiuser systems.
>
> I never get to see a complete compare.
>
> This is the output from the command-line:
>
> ---------------
> Box Backup Query Tool vtrunk_625, (c) Ben Summers and contributors  
> 2003-2006
> Using configuration file bbackupd.conf
> Connecting to store...
> Handshake with store...
> Login to store...
> Login complete.
>
> Type "help" for a list of commands.
>
> WARNING: Quick compare used -- file attributes are not checked.
> Unable to send message to Event Log: error 6:
> Failed to open file C:\miranda\\blah.dat: error 32
> ERROR: (1/2) during file fetch and comparison for '/miranda/blah.dat'
> ERROR: (7/42) during file fetch and comparison for '/miranda/ 
> miranda32.exe'
> ERROR: (7/42) during file fetch and comparison for '/miranda/ 
> mirandaboot.ini'
>
> [ 0 (of 0) differences probably due to file modifications after the  
> last upload
> ]
> Differences: 0 (0 dirs excluded, 0 files excluded)
> Logging off...
> Exception: Connection Protocol_ObjTooBig (7/42)
> ---------------
>
>
> Error 32 means a sharing violation:
> http://msdn.microsoft.com/library/en-us/debug/base/ 
> system_error_codes__0-499_.asp?frame=true
>
> It should continue even when encountering such a file.
>
> After digging in the code, I noticed that this bug should affect  
> the *nix version as well, but since mandatory locks seldom occur,  
> this bug has never bitten me on Linux and OpenBSD.
>
> The problem occurs in BackupQueries.cpp, at line 1425 (trunk, rev.  
> 626). Since the file is locked, the FileStream() constructor in  
> CompareFileContentsAgainstBlockIndex() throws an exception, which  
> goes all to the catch() block where an error is printed, and then  
> the loop proceeds to the next file. The problem is, before that  
> throw(), the download for our locked file had already been  
> "scheduled". Thus, when reading the stream, I guess what we get is  
> the file from the previous iteration since mrConnection is not  
> flushed on error.
>
> Here is a patch which fixes this issue. I'm not sure if it is the  
> right solution, but it should at least outline the source of the  
> problem.
>
> Pascal
> Index: lib/backupclient/BackupStoreFile.cpp
> ===================================================================
> --- lib/backupclient/BackupStoreFile.cpp	(revision 626)
> +++ lib/backupclient/BackupStoreFile.cpp	(working copy)
> @@ -1225,7 +1225,51 @@
>  }
>
>
> +//  
> ---------------------------------------------------------------------- 
> ----
> +//
> +// Function
> +//		Name:    BackupStoreFile::FlushStream(IOStream &, int)
> +//		Purpose: Flushes the stream. Returns true on success.
> +//		Created: 20/6/06
> +//
> +//  
> ---------------------------------------------------------------------- 
> ----
> +bool BackupStoreFile::FlushStream(IOStream &rBlockIndex, int Timeout)
> +{
> +	// Read header
> +	file_BlockIndexHeader hdr;
> +	if(!rBlockIndex.ReadFullBuffer(&hdr, sizeof(hdr), 0 /* not  
> interested in bytes read if this fails */, Timeout))
> +	{
> +		// Couldn't read header
> +		THROW_EXCEPTION(BackupStoreException,  
> CouldntReadEntireStructureFromStream)
> +	}
>
> +	// Check magic
> +	if(hdr.mMagicValue != (int32_t)htonl 
> (OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
> +#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
> +		&& hdr.mMagicValue != (int32_t)htonl 
> (OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V0)
> +#endif
> +		)
> +	{
> +		THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
> +	}
> +
> +	// Get basic information
> +	int64_t numBlocks = box_ntoh64(hdr.mNumBlocks);
> +	
> +	for(int64_t b = 0; b < numBlocks; ++b)
> +	{
> +		// Read an entry from the stream
> +		file_BlockIndexEntry entry;
> +		if(!rBlockIndex.ReadFullBuffer(&entry, sizeof(entry), 0 /* not  
> interested in bytes read if this fails */, Timeout))
> +		{
> +			// Couldn't read entry
> +			THROW_EXCEPTION(BackupStoreException,  
> CouldntReadEntireStructureFromStream)
> +		}	
> +	}
> +	
> +	return true;
> +}
> +
>  //  
> ---------------------------------------------------------------------- 
> ----
>  //
>  // Function
> Index: lib/backupclient/BackupStoreFile.h
> ===================================================================
> --- lib/backupclient/BackupStoreFile.h	(revision 626)
> +++ lib/backupclient/BackupStoreFile.h	(working copy)
> @@ -133,6 +133,7 @@
>  	static void DecodeFile(IOStream &rEncodedFile, const char  
> *DecodedFilename, int Timeout, const BackupClientFileAttributes  
> *pAlterativeAttr = 0);
>  	static std::auto_ptr<BackupStoreFile::DecodedStream>  
> DecodeFileStream(IOStream &rEncodedFile, int Timeout, const  
> BackupClientFileAttributes *pAlterativeAttr = 0);
>  	static bool CompareFileContentsAgainstBlockIndex(const char  
> *Filename, IOStream &rBlockIndex, int Timeout);
> +	static bool FlushStream(IOStream &rBlockIndex, int Timeout);
>  	static std::auto_ptr<IOStream> CombineFileIndices(IOStream  
> &rDiff, IOStream &rFrom, bool DiffIsIndexOnly = false, bool  
> FromIsIndexOnly = false);
>
>  	// Stream manipulation
> Index: bin/bbackupquery/BackupQueries.cpp
> ===================================================================
> --- bin/bbackupquery/BackupQueries.cpp	(revision 626)
> +++ bin/bbackupquery/BackupQueries.cpp	(working copy)
> @@ -1422,7 +1422,15 @@
>  						std::auto_ptr<IOStream> blockIndexStream 
> (mrConnection.ReceiveStream());
>  						
>  						// Compare
> -						equal = BackupStoreFile::CompareFileContentsAgainstBlockIndex 
> (localPath.c_str(), *blockIndexStream, mrConnection.GetTimeout());
> +						try
> +						{
> +							equal =  
> BackupStoreFile::CompareFileContentsAgainstBlockIndex 
> (localPath.c_str(), *blockIndexStream, mrConnection.GetTimeout());
> +						}
> +						catch(...)
> +						{
> +							BackupStoreFile::FlushStream(*blockIndexStream,  
> mrConnection.GetTimeout());
> +							throw;
> +						}
>  					}
>  					else
>  					{