/* * Copyright 1995, 1996 Perforce Software. All rights reserved. * * This file is part of Perforce - the FAST SCM System. */ /* * filegen.cc -- generic part of filesystem interface FileSys */ # ifdef USE_EBCDIC # define NEED_EBCDIC # endif # include <stdhdrs.h> # include <error.h> # include <strbuf.h> # include "filesys.h" # include "md5.h" # include <sha1.h> # include <sha256.h> void FileSys::Digest( StrBuf *digest, Error *e ) { // Use MD5 message digest algorithm to fingerprint the file. MD5 md5; Open( FOM_READ, e ); // Read some StrFixed buf( BufferSize() ); while( !e->Test() ) { int l = Read( buf.Text(), buf.Length(), e ); if( !l || e->Test() ) break; // Since the server MD5 is done as ASCII, so must this. # ifdef USE_EBCDIC if( IsTextual() ) __etoa_l( buf.Text(), l ); # endif StrRef z; z.Set( buf.Text(), l ); md5.Update( z ); } Close( e ); md5.Final( *digest ); } int FileSys::ReadLine( StrBuf *buf, Error *e ) { char b = 0; buf->Clear(); int size = BufferSize(); // Read line into buffer; return 0 on eof // At most BufferSize, to be bug-for-bug compatible // w/ previous versions. while( buf->Length() < size && Read( &b, 1, e ) == 1 && b != '\n' ) buf->Extend( b ); if( !buf->Length() && !b ) return 0; // Make sure our null is there buf->Terminate(); return b == '\n' ? 1 : -1; } void FileSys::ReadWhole( StrBuf *buf, Error *e ) { buf->Clear(); int size = BufferSize(); for(;;) { char *b = buf->Alloc( size ); int l = Read( b, size, e ); if( l < 0 ) l = 0; buf->SetEnd( b + l ); if( e->Test() || !l ) break; } buf->Terminate(); } /* * FileSys::ReadFile() - open, read whole file into string, close */ void FileSys::ReadFile( StrBuf *buf, Error *e ) { Open( FOM_READ, e ); if( e->Test() ) return; ReadWhole( buf, e ); if( e->Test() ) return; Close( e ); } /* * FileSys::WriteFile() - open, write whole file from string, close */ void FileSys::WriteFile( const StrPtr *buf, Error *e ) { Open( FOM_WRITE, e ); if( e->Test() ) return; Write( buf->Text(), buf->Length(), e ); if( e->Test() ) return; Close( e ); } /* * FileSys::Compare() - do direct comparison of files */ int FileSys::Compare( FileSys *other, Error *e ) { int diff = 0; Open( FOM_READ, e ); if( e->Test() ) return 0; other->Open( FOM_READ, e ); if( e->Test() ) { Close( e ); return 0; } StrFixed buf1( BufferSize() ); StrFixed buf2( BufferSize() ); while( !diff ) { int l1 = Read( buf1.Text(), buf1.Length(), e ); int l2 = other->Read( buf2.Text(), buf2.Length(), e ); if( e->Test() ) break; diff = l1 != l2 || memcmp( buf1.Text(), buf2.Text(), l1 ); if( !l1 ) break; } Close( e ); other->Close( e ); return diff; } /* * FileSys::Copy - copy one file to another */ void FileSys::Copy( FileSys *targetFile, FilePerm perms, Error *e ) { // Open source and target files. Open( FOM_READ, e ); if( e->Test() ) return; targetFile->Perms( perms ); targetFile->Open( FOM_WRITE, e ); if( e->Test() ) { Close( e ); return; } // Copy text StrFixed buf( BufferSize() ); while( !e->Test() ) { int l = Read( buf.Text(), buf.Length(), e ); if( !l || e->Test() ) break; targetFile->Write( buf.Text(), l, e ); } // Close off files Close( e ); targetFile->Close( e ); targetFile->Chmod( perms, e ); } /* * FileSys::Chmod2() * * If Chmod() doesn't work, it may because we don't own the file. * Another approach is to copy the file to get ownership and thus * set the permission. */ void FileSys::Chmod2( FilePerm perms, Error *e ) { // First just try chmod -- maybe we own it Chmod( perms, e ); if( !e->Test() ) return; // No, now try copying to get ownership and perms. Error ec; FileSys *tmpFile = CreateTemp( GetType() ); tmpFile->MakeLocalTemp( Name() ); if( !ec.Test() ) Copy( tmpFile, perms, &ec ); if( !ec.Test() ) tmpFile->Rename( this, &ec ); delete tmpFile; // If copy unsuccessful -- use just return Chmod() error if( !ec.Test() ) e->Clear(); } void FileSys::ComputeDigest( FileDigestType digType, StrBuf *digest, Error *e ) { if( digType == FS_DIGEST_MD5 ) { Digest( digest, e ); return; } else if( digType == FS_DIGEST_GIT_TEXT_SHA1 ) { Sha1 sha1; Sha1Digester sha1Digester; int l; StrFixed buf( 4096 ); P4INT64 fileSize = 0; Open( FOM_READ, e ); while( !e->Test() && ( l = Read( buf.Text(), buf.Length(), e ) ) > 0 ) fileSize += l; Close( e ); if( e->Test() ) return; StrNum fSizeFmt( fileSize ); sha1Digester.Update( StrRef( "blob " ) ); sha1Digester.Update( fSizeFmt ); sha1Digester.Update( StrRef( "\0", 1 ) ); Open( FOM_READ, e ); while( !e->Test() ) { int l = Read( buf.Text(), buf.Length(), e ); if( !l || e->Test() ) break; sha1Digester.Update( StrRef( buf.Text(), l ) ); } Close( e ); sha1Digester.Final( sha1 ); sha1.Fmt( *digest ); } else if( digType == FS_DIGEST_GIT_BINARY_SHA1 ) { Sha1 sha1; Sha1Digester sha1Digester; int l; StrFixed buf( 4096 ); StrNum fSizeFmt( GetSize() ); sha1Digester.Update( StrRef( "blob " ) ); sha1Digester.Update( fSizeFmt ); sha1Digester.Update( StrRef( "\0", 1 ) ); Open( FOM_READ, e ); while( !e->Test() ) { int l = Read( buf.Text(), buf.Length(), e ); if( !l || e->Test() ) break; sha1Digester.Update( StrRef( buf.Text(), l ) ); } Close( e ); sha1Digester.Final( sha1 ); sha1.Fmt( *digest ); } else if( digType == FS_DIGEST_SHA256 ) { Sha256 sha256; Sha256Digester sha256Digester; int l; StrFixed buf( 4096 ); Open( FOM_READ, e ); if( e->Test() ) return; while( !e->Test() ) { int l = Read( buf.Text(), buf.Length(), e ); if( !l || e->Test() ) break; sha256Digester.Update( StrRef( buf.Text(), l ) ); } Close( e ); if( e->Test() ) return; sha256Digester.Final( sha256.data ); sha256.Fmt( *digest ); } }