2021-11-19 08:09:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Copyright (c) 2015-2021 MinIO, Inc.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// This file is part of MinIO Object Storage stack
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// This program is free software: you can redistribute it and/or modify
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// it under the terms of the GNU Affero General Public License as published by
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// the Free Software Foundation, either version 3 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 Affero General Public License for more details.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// You should have received a copy of the GNU Affero General Public License
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// along with this program.  If not, see <http://www.gnu.org/licenses/>.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-11-19 04:15:22 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								package  cmd  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
									
										
										
										
											2024-06-08 06:18:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"slices" 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-20 09:54:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"sort" 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-19 04:15:22 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"testing" 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-20 09:54:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"time" 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-19 04:15:22 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-11-20 09:54:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/internal/bucket/lifecycle" 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-19 04:15:22 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									xhttp  "github.com/minio/minio/internal/http" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  Test_hashDeterministicString ( t  * testing . T )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									tests  :=  [ ] struct  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										name  string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										arg   map [ string ] string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											name :  "zero" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											arg :   map [ string ] string { } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											name :  "nil" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											arg :   nil , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											name :  "one" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											arg :   map [ string ] string { "key" :  "value" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											name :  "several" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											arg :  map [ string ] string { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												xhttp . AmzRestore :                  "FAILED" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												xhttp . ContentMD5 :                  mustGetUUID ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												xhttp . AmzBucketReplicationStatus :  "PENDING" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												xhttp . ContentType :                 "application/json" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											name :  "someempty" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											arg :  map [ string ] string { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												xhttp . AmzRestore :                  "" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												xhttp . ContentMD5 :                  mustGetUUID ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												xhttp . AmzBucketReplicationStatus :  "" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												xhttp . ContentType :                 "application/json" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  tt  :=  range  tests  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										t . Run ( tt . name ,  func ( t  * testing . T )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											const  n  =  100 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											want  :=  hashDeterministicString ( tt . arg ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											m  :=  tt . arg 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											for  i  :=  0 ;  i  <  n ;  i ++  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  got  :=  hashDeterministicString ( m ) ;  got  !=  want  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													t . Errorf ( "hashDeterministicString() = %v, want %v" ,  got ,  want ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Check casual collisions
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  m  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												m  =  make ( map [ string ] string ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											m [ "12312312" ]  =  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  got  :=  hashDeterministicString ( m ) ;  got  ==  want  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												t . Errorf ( "hashDeterministicString() = %v, does not want %v" ,  got ,  want ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											want  =  hashDeterministicString ( m ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											delete ( m ,  "12312312" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											m [ "another" ]  =  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  got  :=  hashDeterministicString ( m ) ;  got  ==  want  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												t . Errorf ( "hashDeterministicString() = %v, does not want %v" ,  got ,  want ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											want  =  hashDeterministicString ( m ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											m [ "another" ]  =  "hashDeterministicString" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  got  :=  hashDeterministicString ( m ) ;  got  ==  want  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												t . Errorf ( "hashDeterministicString() = %v, does not want %v" ,  got ,  want ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											want  =  hashDeterministicString ( m ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											m [ "another" ]  =  "hashDeterministicStringhashDeterministicStringhashDeterministicStringhashDeterministicStringhashDeterministicStringhashDeterministicStringhashDeterministicString" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  got  :=  hashDeterministicString ( m ) ;  got  ==  want  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												t . Errorf ( "hashDeterministicString() = %v, does not want %v" ,  got ,  want ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Flip key/value
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											want  =  hashDeterministicString ( m ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											delete ( m ,  "another" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											m [ "hashDeterministicStringhashDeterministicStringhashDeterministicStringhashDeterministicStringhashDeterministicStringhashDeterministicStringhashDeterministicString" ]  =  "another" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  got  :=  hashDeterministicString ( m ) ;  got  ==  want  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												t . Errorf ( "hashDeterministicString() = %v, does not want %v" ,  got ,  want ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2021-11-20 09:54:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  TestGetFileInfoVersions ( t  * testing . T )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									basefi  :=  FileInfo { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Volume :            "volume" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Name :              "object-name" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										VersionID :         "756100c6-b393-4981-928a-d49bbc164741" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										IsLatest :          true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Deleted :           false , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										TransitionStatus :  "" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										DataDir :           "bffea160-ca7f-465f-98bc-9b4f1c3ba1ef" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										XLV1 :              false , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ModTime :           time . Now ( ) . UTC ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Size :              0 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Mode :              0 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Metadata :          nil , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Parts :             nil , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Erasure :  ErasureInfo { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Algorithm :     ReedSolomon . String ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											DataBlocks :    4 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ParityBlocks :  2 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											BlockSize :     10000 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Index :         1 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Distribution :  [ ] int { 1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ,  8 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Checksums :  [ ] ChecksumInfo { { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												PartNumber :  1 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												Algorithm :   HighwayHash256S , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												Hash :        nil , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										MarkDeleted :       false , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										NumVersions :       1 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										SuccessorModTime :  time . Time { } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									xl  :=  xlMetaV2 { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  versions  [ ] FileInfo 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-08 06:18:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  allVersionIDs ,  freeVersionIDs  [ ] string 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-20 09:54:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  i  :=  0 ;  i  <  5 ;  i ++  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fi  :=  basefi 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fi . VersionID  =  mustGetUUID ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fi . DataDir  =  mustGetUUID ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fi . ModTime  =  basefi . ModTime . Add ( time . Duration ( i )  *  time . Second ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  :=  xl . AddVersion ( fi ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											t . Fatalf ( "%d: Failed to add version %v" ,  i + 1 ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  i  >  3  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Simulate transition of a version
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											transfi  :=  fi 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											transfi . TransitionStatus  =  lifecycle . TransitionComplete 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											transfi . TransitionTier  =  "MINIO-TIER" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											transfi . TransitionedObjName  =  mustGetUUID ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											xl . DeleteVersion ( transfi ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fi . SetTierFreeVersionID ( mustGetUUID ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// delete this version leading to a free version
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											xl . DeleteVersion ( fi ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											freeVersionIDs  =  append ( freeVersionIDs ,  fi . TierFreeVersionID ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-08 06:18:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											allVersionIDs  =  append ( allVersionIDs ,  fi . TierFreeVersionID ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-20 09:54:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											versions  =  append ( versions ,  fi ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-08 06:18:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											allVersionIDs  =  append ( allVersionIDs ,  fi . VersionID ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-20 09:54:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf ,  err  :=  xl . AppendTo ( nil ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										t . Fatalf ( "Failed to serialize xlmeta %v" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-08 23:29:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fivs ,  err  :=  getFileInfoVersions ( buf ,  basefi . Volume ,  basefi . Name ,  false ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-20 09:54:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										t . Fatalf ( "getFileInfoVersions failed: %v" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-08 06:18:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									chkNumVersions  :=  func ( fis  [ ] FileInfo )  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  i  :=  0 ;  i  <  len ( fis ) - 1 ;  i ++  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  fis [ i ] . NumVersions  !=  fis [ i + 1 ] . NumVersions  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! chkNumVersions ( fivs . Versions )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										t . Fatalf ( "Expected all versions to have the same NumVersions" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-20 09:54:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sort . Slice ( versions ,  func ( i ,  j  int )  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  versions [ i ] . IsLatest  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  versions [ j ] . IsLatest  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  versions [ i ] . ModTime . After ( versions [ j ] . ModTime ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i ,  fi  :=  range  fivs . Versions  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  fi . VersionID  !=  versions [ i ] . VersionID  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											t . Fatalf ( "getFileInfoVersions: versions don't match at %d, version id expected %s but got %s" ,  i ,  fi . VersionID ,  versions [ i ] . VersionID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-08 06:18:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  fi . NumVersions  !=  len ( fivs . Versions )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											t . Fatalf ( "getFileInfoVersions: version with %s version id expected to have %d as NumVersions but got %d" ,  fi . VersionID ,  len ( fivs . Versions ) ,  fi . NumVersions ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-20 09:54:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i ,  free  :=  range  fivs . FreeVersions  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  free . VersionID  !=  freeVersionIDs [ i ]  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											t . Fatalf ( "getFileInfoVersions: free versions don't match at %d, version id expected %s but got %s" ,  i ,  free . VersionID ,  freeVersionIDs [ i ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-08 06:18:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// versions are stored in xl-meta sorted in descending order of their ModTime
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									slices . Reverse ( allVersionIDs ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-08-08 23:29:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fivs ,  err  =  getFileInfoVersions ( buf ,  basefi . Volume ,  basefi . Name ,  true ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-08 06:18:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										t . Fatalf ( "getFileInfoVersions failed: %v" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! chkNumVersions ( fivs . Versions )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										t . Fatalf ( "Expected all versions to have the same NumVersions" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i ,  fi  :=  range  fivs . Versions  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  fi . VersionID  !=  allVersionIDs [ i ]  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											t . Fatalf ( "getFileInfoVersions: all versions don't match at %d expected %s but got %s" ,  i ,  allVersionIDs [ i ] ,  fi . VersionID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-20 09:54:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}