2014-01-19 21:39:38 +04:00
#!/usr/bin/env gjs
//
// Copyright (C) 2014 Colin Walters <walters@verbum.org>
//
2018-01-30 22:26:26 +03:00
// SPDX-License-Identifier: LGPL-2.0+
//
2014-01-19 21:39:38 +04:00
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
2021-12-07 04:20:55 +03:00
// License along with this library. If not, see <https://www.gnu.org/licenses/>.
2014-01-19 21:39:38 +04:00
const GLib = imports . gi . GLib ;
const Gio = imports . gi . Gio ;
const OSTree = imports . gi . OSTree ;
let repoPathArg = ARGV [ 0 ] ;
let refToCorrupt = ARGV [ 1 ] ;
let repo = OSTree . Repo . new ( Gio . File . new _for _path ( repoPathArg ) ) ;
repo . open ( null ) ;
function listObjectChecksumsRecurse ( dir , allObjects ) {
dir . ensure _resolved ( ) ;
allObjects [ dir . tree _get _contents _checksum ( ) + '.dirtree' ] = true ;
allObjects [ dir . get _checksum ( ) + '.dirmeta' ] = true ;
let e = dir . enumerate _children ( 'standard::name,standard::type' , 0 , null ) ;
let info ;
while ( ( info = e . next _file ( null ) ) != null ) {
let child = e . get _child ( info ) ;
child . ensure _resolved ( ) ;
print ( info . get _name ( ) + " is " + info . get _file _type ( ) ) ;
if ( info . get _file _type ( ) == Gio . FileType . DIRECTORY ) {
listObjectChecksumsRecurse ( child , allObjects ) ;
} else {
allObjects [ child . get _checksum ( ) + '.filez' ] = true ;
}
}
e . close ( null ) ;
}
let [ , root , commit ] = repo . read _commit ( refToCorrupt , null ) ;
let allObjects = { } ;
allObjects [ commit + '.commit' ] = true ;
listObjectChecksumsRecurse ( root , allObjects ) ;
let i = 0 ;
for ( let v in allObjects )
i ++ ;
print ( "commit " + commit + " refers to " + i + " objects" ) ;
let offset = GLib . random _int _range ( 0 , i ) ;
let objectToCorrupt = null ;
for ( let v in allObjects ) {
if ( offset <= 0 ) {
objectToCorrupt = v ;
break ;
}
offset -- ;
}
print ( "Choosing " + objectToCorrupt + " to corrupt" ) ;
let loosePath = repo . get _path ( ) . resolve _relative _path ( 'objects/' + objectToCorrupt . substring ( 0 , 2 ) + "/" + objectToCorrupt . substring ( 2 ) ) ;
let iostream = loosePath . open _readwrite ( null ) ;
let info = iostream . query _info ( 'standard::size' , null ) ;
let size = info . get _size ( ) ;
let datain = Gio . DataInputStream . new ( iostream . get _input _stream ( ) ) ;
let dataout = Gio . DataOutputStream . new ( iostream . get _output _stream ( ) ) ;
2014-10-22 21:52:12 +04:00
let bytesToChange = 10 ;
let status = "" ;
var bytesChanged = { }
for ( i = 0 ; i < bytesToChange ; i ++ ) {
let byteOffsetToCorrupt ;
do {
byteOffsetToCorrupt = GLib . random _int _range ( 0 , size ) ;
} while ( byteOffsetToCorrupt in bytesChanged ) ;
iostream . seek ( byteOffsetToCorrupt , GLib . SeekType . SET , null ) ;
let inbyte = datain . read _byte ( null ) ;
let outbyte = ( inbyte + 1 ) % 255 ;
dataout . put _byte ( outbyte , null ) ;
bytesChanged [ byteOffsetToCorrupt ] = byteOffsetToCorrupt ;
status += "Changed byte offset " + byteOffsetToCorrupt + " from " + inbyte + " to " + outbyte + "\n" ;
}
2014-01-19 21:39:38 +04:00
dataout . flush ( null ) ;
iostream . close ( null ) ;
2014-10-22 21:52:12 +04:00
print ( status ) ;
2014-01-19 21:39:38 +04:00
let successFile = Gio . File . new _for _path ( 'corrupted-status.txt' ) ;
successFile . replace _contents ( status , null , false , 0 , null ) ;