2025-04-04 21:15:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Copyright (c) 2015-2025 MinIO, Inc.
  
						 
					
						
							
								
									
										
										
										
											2021-04-19 03:41:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// 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/>.
  
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-08-19 07:23:42 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								package  cmd  
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
									
										
										
										
											2018-03-15 03:01:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"context" 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-26 01:52:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"encoding/base64" 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-15 07:47:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"errors" 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"fmt" 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 20:58:18 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"io" 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:52:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"os" 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"path" 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-16 04:55:23 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"sort" 
							 
						 
					
						
							
								
									
										
										
										
											2018-09-28 11:36:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"strconv" 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 04:35:43 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"strings" 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-12 02:22:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"sync" 
							 
						 
					
						
							
								
									
										
										
										
											2020-08-22 12:39:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"time" 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 04:35:43 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-01-15 02:01:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/klauspost/readahead" 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-15 00:38:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio-go/v7/pkg/set" 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-29 09:44:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/internal/config/storageclass" 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/internal/crypto" 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/internal/hash" 
							 
						 
					
						
							
								
									
										
										
										
											2021-06-02 05:59:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									xhttp  "github.com/minio/minio/internal/http" 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-15 03:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									xioutil  "github.com/minio/minio/internal/ioutil" 
							 
						 
					
						
							
								
									
										
										
										
											2021-06-02 05:59:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/internal/logger" 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-25 07:05:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/pkg/v3/mimedb" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/minio/pkg/v3/sync/errgroup" 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-12 02:35:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/sio" 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  getUploadIDDir ( bucket ,  object ,  uploadID  string )  string  {  
						 
					
						
							
								
									
										
										
										
											2022-10-26 01:52:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									uploadUUID  :=  uploadID 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-10 08:41:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									uploadBytes ,  err  :=  base64 . RawURLEncoding . DecodeString ( uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-26 01:52:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										slc  :=  strings . SplitN ( string ( uploadBytes ) ,  "." ,  2 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  len ( slc )  ==  2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											uploadUUID  =  slc [ 1 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  pathJoin ( er . getMultipartSHADir ( bucket ,  object ) ,  uploadUUID ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-01-27 04:51:12 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  getMultipartSHADir ( bucket ,  object  string )  string  {  
						 
					
						
							
								
									
										
										
										
											2018-03-16 04:55:23 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									return  getSHA256Hash ( [ ] byte ( pathJoin ( bucket ,  object ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-01-27 04:51:12 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-04-24 05:54:28 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// checkUploadIDExists - verify if a given uploadID exists and is valid.
  
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  checkUploadIDExists ( ctx  context . Context ,  bucket ,  object ,  uploadID  string ,  write  bool )  ( fi  FileInfo ,  metArr  [ ] FileInfo ,  err  error )  {  
						 
					
						
							
								
									
										
										
										
											2021-03-27 02:17:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  errors . Is ( err ,  errFileNotFound )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-27 02:17:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											err  =  errUploadIDNotFound 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									uploadIDPath  :=  er . getUploadIDDir ( bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									storageDisks  :=  er . getDisks ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-27 01:30:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Read metadata associated with the object from all disks.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									partsMetadata ,  errs  :=  readAllFileInfo ( ctx ,  storageDisks ,  bucket ,  minioMetaMultipartBucket , 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-21 13:33:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										uploadIDPath ,  "" ,  false ,  false ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-27 01:30:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									readQuorum ,  writeQuorum ,  err  :=  objectQuorumFromMeta ( ctx ,  partsMetadata ,  errs ,  er . defaultParityCount ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-27 01:30:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  fi ,  nil ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-27 01:30:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  readQuorum  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  fi ,  nil ,  errErasureReadQuorum 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  writeQuorum  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  fi ,  nil ,  errErasureWriteQuorum 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-04-26 01:13:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									quorum  :=  readQuorum 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  write  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										quorum  =  writeQuorum 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-18 10:18:20 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// List all online disks.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-18 10:18:20 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									_ ,  modTime ,  etag  :=  listOnlineDisks ( storageDisks ,  partsMetadata ,  errs ,  quorum ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  write  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										err  =  reduceWriteQuorumErrs ( ctx ,  errs ,  objectOpIgnoredErrs ,  writeQuorum ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										err  =  reduceReadQuorumErrs ( ctx ,  errs ,  objectOpIgnoredErrs ,  readQuorum ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  fi ,  nil ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-27 01:30:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Pick one from the first valid metadata.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-18 10:18:20 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fi ,  err  =  pickValidFileInfo ( ctx ,  partsMetadata ,  modTime ,  etag ,  quorum ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  fi ,  partsMetadata ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2017-01-27 04:51:12 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-08-22 04:14:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// cleanupMultipartPath removes all extraneous files and parts from the multipart folder, this is used per CompleteMultipart.
  
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// do not use this function outside of completeMultipartUpload()
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  cleanupMultipartPath ( ctx  context . Context ,  paths  ... string )  {  
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									storageDisks  :=  er . getDisks ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-15 00:44:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									g  :=  errgroup . WithNErrs ( len ( storageDisks ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  index ,  disk  :=  range  storageDisks  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-01-27 04:51:12 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										if  disk  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-15 00:44:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										index  :=  index 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										g . Go ( func ( )  error  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											_  =  storageDisks [ index ] . DeleteBulk ( ctx ,  minioMetaMultipartBucket ,  paths ... ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-15 00:44:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} ,  index ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-01-27 04:51:12 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-15 00:44:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									g . Wait ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-01-27 04:51:12 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-08-22 12:39:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Clean-up the old multipart uploads. Should be run in a Go routine.
  
						 
					
						
							
								
									
										
										
										
											2024-07-31 03:01:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  cleanupStaleUploads ( ctx  context . Context )  {  
						 
					
						
							
								
									
										
										
										
											2020-12-10 23:28:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// run multiple cleanup's local to this server.
 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-12 02:22:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  wg  sync . WaitGroup 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-25 14:33:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  _ ,  disk  :=  range  er . getLocalDisks ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-12-10 23:28:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  disk  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-12 02:22:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											wg . Add ( 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											go  func ( disk  StorageAPI )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												defer  wg . Done ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-31 03:01:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												er . cleanupStaleUploadsOnDisk ( ctx ,  disk ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-12 02:22:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} ( disk ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-08-22 12:39:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-12 02:22:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									wg . Wait ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  deleteAll ( ctx  context . Context ,  bucket ,  prefix  string )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  wg  sync . WaitGroup 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  disk  :=  range  er . getDisks ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  disk  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										wg . Add ( 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										go  func ( disk  StorageAPI )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											defer  wg . Done ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-12 00:15:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											disk . Delete ( ctx ,  bucket ,  prefix ,  DeleteOptions { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												Recursive :  true , 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-29 14:35:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												Immediate :  false , 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-12 00:15:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-12 02:22:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} ( disk ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									wg . Wait ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-08-22 12:39:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Remove the old multipart uploads on the given disk.
  
						 
					
						
							
								
									
										
										
										
											2024-07-31 03:01:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  cleanupStaleUploadsOnDisk ( ctx  context . Context ,  disk  StorageAPI )  {  
						 
					
						
							
								
									
										
										
										
											2024-04-15 18:02:39 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									drivePath  :=  disk . Endpoint ( ) . Path 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:52:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-04-15 18:02:39 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									readDirFn ( pathJoin ( drivePath ,  minioMetaMultipartBucket ) ,  func ( shaDir  string ,  typ  os . FileMode )  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										readDirFn ( pathJoin ( drivePath ,  minioMetaMultipartBucket ,  shaDir ) ,  func ( uploadIDDir  string ,  typ  os . FileMode )  error  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-08-22 12:39:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											uploadIDPath  :=  pathJoin ( shaDir ,  uploadIDDir ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-18 00:40:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											var  modTime  time . Time 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Upload IDs are of the form base64_url(<UUID>x<UnixNano>), we can extract the time from the UUID.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  b64 ,  err  :=  base64 . RawURLEncoding . DecodeString ( uploadIDDir ) ;  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  split  :=  strings . Split ( string ( b64 ) ,  "x" ) ;  len ( split )  ==  2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													t ,  err  :=  strconv . ParseInt ( split [ 1 ] ,  10 ,  64 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														modTime  =  time . Unix ( 0 ,  t ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Fallback for older uploads without time in the ID.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  modTime . IsZero ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												wait  :=  deleteMultipartCleanupSleeper . Timer ( ctx ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												fi ,  err  :=  disk . ReadVersion ( ctx ,  "" ,  minioMetaMultipartBucket ,  uploadIDPath ,  "" ,  ReadOptions { } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												modTime  =  fi . ModTime 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												wait ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-31 03:01:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  time . Since ( modTime )  <  globalAPIConfig . getStaleUploadsExpiry ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:52:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return  nil 
							 
						 
					
						
							
								
									
										
										
										
											2020-08-22 12:39:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-28 01:15:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											w  :=  xioutil . NewDeadlineWorker ( globalDriveConfig . GetMaxTimeout ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-15 03:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  w . Run ( func ( )  error  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-15 18:02:39 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												wait  :=  deleteMultipartCleanupSleeper . Timer ( ctx ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-18 00:40:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												pathUUID  :=  mustGetUUID ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												targetPath  :=  pathJoin ( drivePath ,  minioMetaTmpDeletedBucket ,  pathUUID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												renameAll ( pathJoin ( drivePath ,  minioMetaMultipartBucket ,  uploadIDPath ) ,  targetPath ,  pathJoin ( drivePath ,  minioMetaBucket ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-15 03:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												wait ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:52:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-18 00:40:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Get the modtime of the shaDir.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-31 00:56:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										vi ,  err  :=  disk . StatVol ( ctx ,  pathJoin ( minioMetaMultipartBucket ,  shaDir ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-18 00:40:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Modtime is returned in the Created field. See (*xlStorage).StatVol
 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-31 03:01:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  time . Since ( vi . Created )  <  globalAPIConfig . getStaleUploadsExpiry ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-18 00:40:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-28 01:15:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										w  :=  xioutil . NewDeadlineWorker ( globalDriveConfig . GetMaxTimeout ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-15 03:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  w . Run ( func ( )  error  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-15 18:02:39 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											wait  :=  deleteMultipartCleanupSleeper . Timer ( ctx ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-18 00:40:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											pathUUID  :=  mustGetUUID ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											targetPath  :=  pathJoin ( drivePath ,  minioMetaTmpDeletedBucket ,  pathUUID ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-15 18:02:39 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-18 00:40:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											// We are not deleting shaDir recursively here, if shaDir is empty
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// and its older then we can happily delete it.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Rename ( pathJoin ( drivePath ,  minioMetaMultipartBucket ,  shaDir ) ,  targetPath ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-15 03:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											wait ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:52:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-04-15 18:02:39 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									readDirFn ( pathJoin ( drivePath ,  minioMetaTmpBucket ) ,  func ( tmpDir  string ,  typ  os . FileMode )  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  strings . HasPrefix ( tmpDir ,  ".trash" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// do not remove .trash/ here, it has its own routines
 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:52:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  nil 
							 
						 
					
						
							
								
									
										
										
										
											2020-08-22 12:39:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-12 02:22:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										vi ,  err  :=  disk . StatVol ( ctx ,  pathJoin ( minioMetaTmpBucket ,  tmpDir ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-09 06:55:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:52:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  nil 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-09 06:55:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-28 01:15:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										w  :=  xioutil . NewDeadlineWorker ( globalDriveConfig . GetMaxTimeout ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-15 03:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  w . Run ( func ( )  error  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-15 18:02:39 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											wait  :=  deleteMultipartCleanupSleeper . Timer ( ctx ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-31 03:01:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  time . Since ( vi . Created )  >  globalAPIConfig . getStaleUploadsExpiry ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-15 18:02:39 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												pathUUID  :=  mustGetUUID ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												targetPath  :=  pathJoin ( drivePath ,  minioMetaTmpDeletedBucket ,  pathUUID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												renameAll ( pathJoin ( drivePath ,  minioMetaTmpBucket ,  tmpDir ) ,  targetPath ,  pathJoin ( drivePath ,  minioMetaBucket ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-15 03:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											wait ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-27 01:52:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-08-22 12:39:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-12-01 07:58:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// ListMultipartUploads - lists all the pending multipart
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// uploads for a particular object in a bucket.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Implements minimal S3 compatible ListMultipartUploads API. We do
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// not support prefix based listing, this is a deliberate attempt
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// towards simplification of multipart APIs.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// The resulting ListMultipartsInfo structure is unmarshalled directly as XML.
  
						 
					
						
							
								
									
										
										
										
											2020-07-04 10:27:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  ListMultipartUploads ( ctx  context . Context ,  bucket ,  object ,  keyMarker ,  uploadIDMarker ,  delimiter  string ,  maxUploads  int )  ( result  ListMultipartsInfo ,  err  error )  {  
						 
					
						
							
								
									
										
										
										
											2024-08-14 06:22:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									auditObjectErasureSet ( ctx ,  "ListMultipartUploads" ,  object ,  & er ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-04 15:45:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-12-01 07:58:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									result . MaxUploads  =  maxUploads 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result . KeyMarker  =  keyMarker 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result . Prefix  =  object 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result . Delimiter  =  delimiter 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-07-04 10:27:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  uploadIDs  [ ] string 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  disk  StorageAPI 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-25 14:33:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									disks  :=  er . getOnlineLocalDisks ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-15 23:34:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  len ( disks )  ==  0  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-18 00:40:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// If no local, get non-healing disks.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  ok  bool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  disks ,  ok  =  er . getOnlineDisksWithHealing ( false ) ;  ! ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											disks  =  er . getOnlineDisks ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-15 23:34:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-18 00:40:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-15 23:34:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  _ ,  disk  =  range  disks  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-11 04:47:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  disk  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! disk . IsOnline ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										uploadIDs ,  err  =  disk . ListDir ( ctx ,  bucket ,  minioMetaMultipartBucket ,  er . getMultipartSHADir ( bucket ,  object ) ,  - 1 ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 07:43:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-15 07:47:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  errors . Is ( err ,  errDiskNotFound )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-04 10:27:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  errors . Is ( err ,  errFileNotFound )  { 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-16 04:55:23 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												return  result ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-04 10:27:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  result ,  toObjectErr ( err ,  bucket ,  object ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 07:43:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-04 10:27:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i  :=  range  uploadIDs  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										uploadIDs [ i ]  =  strings . TrimSuffix ( uploadIDs [ i ] ,  SlashSeparator ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// S3 spec says uploadIDs should be sorted based on initiated time, we need
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// to read the metadata entry.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  uploads  [ ] MultipartInfo 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-02-09 07:22:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									populatedUploadIDs  :=  set . NewStringSet ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-04 10:27:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  _ ,  uploadID  :=  range  uploadIDs  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-09 07:22:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  populatedUploadIDs . Contains ( uploadID )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-04 10:27:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 07:43:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-25 03:06:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// If present, use time stored in ID.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										startTime  :=  time . Now ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  split  :=  strings . Split ( uploadID ,  "x" ) ;  len ( split )  ==  2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											t ,  err  :=  strconv . ParseInt ( split [ 1 ] ,  10 ,  64 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												startTime  =  time . Unix ( 0 ,  t ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-17 04:25:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-01 07:58:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										uploads  =  append ( uploads ,  MultipartInfo { 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-25 03:06:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											Bucket :     bucket , 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											Object :     object , 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-29 10:39:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											UploadID :   base64 . RawURLEncoding . EncodeToString ( fmt . Appendf ( nil ,  "%s.%s" ,  globalDeploymentID ( ) ,  uploadID ) ) , 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-25 03:06:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											Initiated :  startTime , 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-29 10:39:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-09 07:22:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										populatedUploadIDs . Add ( uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2016-12-02 15:15:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-07-04 10:27:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sort . Slice ( uploads ,  func ( i  int ,  j  int )  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  uploads [ i ] . Initiated . Before ( uploads [ j ] . Initiated ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									uploadIndex  :=  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  uploadIDMarker  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  uploadIndex  <  len ( uploads )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  uploads [ uploadIndex ] . UploadID  !=  uploadIDMarker  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												uploadIndex ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  uploads [ uploadIndex ] . UploadID  ==  uploadIDMarker  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												uploadIndex ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											uploadIndex ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  uploadIndex  <  len ( uploads )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										result . Uploads  =  append ( result . Uploads ,  uploads [ uploadIndex ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										result . NextUploadIDMarker  =  uploads [ uploadIndex ] . UploadID 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										uploadIndex ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  len ( result . Uploads )  ==  maxUploads  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result . IsTruncated  =  uploadIndex  <  len ( uploads ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! result . IsTruncated  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										result . NextKeyMarker  =  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										result . NextUploadIDMarker  =  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-12-01 07:58:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									return  result ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 07:43:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 07:43:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// newMultipartUpload - wrapper for initializing a new multipart
  
						 
					
						
							
								
									
										
										
										
											2016-10-25 08:37:18 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// request; returns a unique upload id.
  
						 
					
						
							
								
									
										
										
										
											2016-06-02 07:43:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Internally this function creates 'uploads.json' associated for the
  
						 
					
						
							
								
									
										
										
										
											2016-10-25 08:37:18 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// incoming object at
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// '.minio.sys/multipart/bucket/object/uploads.json' on all the
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// disks. `uploads.json` carries metadata regarding on-going multipart
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// operation(s) on the object.
  
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  newMultipartUpload ( ctx  context . Context ,  bucket  string ,  object  string ,  opts  ObjectOptions )  ( * NewMultipartUploadResult ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2022-09-15 09:44:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  opts . CheckPrecondFn  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-11 08:31:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ! opts . NoLock  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ns  :=  er . NewNSLock ( bucket ,  object ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											lkctx ,  err  :=  ns . GetLock ( ctx ,  globalOperationTimeout ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ctx  =  lkctx . Context ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											defer  ns . Unlock ( lkctx ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											opts . NoLock  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-15 09:44:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-11 08:31:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										obj ,  err  :=  er . getObjectInfo ( ctx ,  bucket ,  object ,  opts ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  ==  nil  &&  opts . CheckPrecondFn ( obj )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-15 09:44:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  nil ,  PreConditionFailed { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-11 08:31:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  err  !=  nil  &&  ! isErrVersionNotFound ( err )  &&  ! isErrObjectNotFound ( err )  &&  ! isErrReadQuorum ( err )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 00:13:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-09 01:43:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// if object doesn't exist return error for If-Match conditional requests
 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 00:13:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// If-None-Match should be allowed to proceed for non-existent objects
 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-09 01:43:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  err  !=  nil  &&  opts . HasIfMatch  &&  ( isErrObjectNotFound ( err )  ||  isErrVersionNotFound ( err ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 00:13:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-15 09:44:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-05-05 19:14:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									userDefined  :=  cloneMSS ( opts . UserDefined ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-27 06:43:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  opts . PreserveETag  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										userDefined [ "etag" ]  =  opts . PreserveETag 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									onlineDisks  :=  er . getDisks ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-23 22:57:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Get parity and data drive count based on storage class metadata
 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-05 19:14:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									parityDrives  :=  globalStorageClass . GetParityForSC ( userDefined [ xhttp . AmzStorageClass ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-28 11:22:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  parityDrives  <  0  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										parityDrives  =  er . defaultParityCount 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-07 13:50:24 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-22 19:28:13 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-03-14 18:38:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  globalStorageClass . AvailabilityOptimized ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// If we have offline disks upgrade the number of erasure codes for this object.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										parityOrig  :=  parityDrives 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  offlineDrives  int 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  disk  :=  range  onlineDisks  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  disk  ==  nil  ||  ! disk . IsOnline ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												parityDrives ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												offlineDrives ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-28 02:38:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-23 22:57:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-03-14 18:38:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  offlineDrives  >=  ( len ( onlineDisks ) + 1 ) / 2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// if offline drives are more than 50% of the drives
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// we have no quorum, we shouldn't proceed just
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// fail at that point.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  toObjectErr ( errErasureWriteQuorum ,  bucket ,  object ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-23 22:57:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-03-14 18:38:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  parityDrives  >=  len ( onlineDisks ) / 2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											parityDrives  =  len ( onlineDisks )  /  2 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-11 04:47:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-03-14 18:38:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  parityOrig  !=  parityDrives  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											userDefined [ minIOErasureUpgraded ]  =  strconv . Itoa ( parityOrig )  +  "->"  +  strconv . Itoa ( parityDrives ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-28 02:38:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-23 22:57:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									dataDrives  :=  len ( onlineDisks )  -  parityDrives 
							 
						 
					
						
							
								
									
										
										
										
											2021-05-28 02:38:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-12-22 19:28:13 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// we now know the number of blocks this object needs for data and parity.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// establish the writeQuorum using this data
 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									writeQuorum  :=  dataDrives 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  dataDrives  ==  parityDrives  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-17 04:08:02 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										writeQuorum ++ 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-10 10:19:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-22 19:28:13 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Initialize parts metadata
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									partsMetadata  :=  make ( [ ] FileInfo ,  len ( onlineDisks ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fi  :=  newFileInfo ( pathJoin ( bucket ,  object ) ,  dataDrives ,  parityDrives ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-25 10:07:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fi . VersionID  =  opts . VersionID 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  opts . Versioned  &&  fi . VersionID  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fi . VersionID  =  mustGetUUID ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									fi . DataDir  =  mustGetUUID ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-14 04:26:02 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ckSum  :=  userDefined [ ReplicationSsecChecksumHeader ] ;  ckSum  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										v ,  err  :=  base64 . StdEncoding . DecodeString ( ckSum ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fi . Checksum  =  v 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-13 14:56:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										delete ( userDefined ,  ReplicationSsecChecksumHeader ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Initialize erasure metadata.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  index  :=  range  partsMetadata  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										partsMetadata [ index ]  =  fi 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-08-15 09:08:42 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Guess content-type from the extension if possible.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-05 19:14:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  userDefined [ "content-type" ]  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										userDefined [ "content-type" ]  =  mimedb . TypeByExtension ( path . Ext ( object ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-04-25 22:33:26 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-02-29 09:44:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// if storageClass is standard no need to save it as part of metadata.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  userDefined [ xhttp . AmzStorageClass ]  ==  storageclass . STANDARD  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										delete ( userDefined ,  xhttp . AmzStorageClass ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  opts . WantChecksum  !=  nil  &&  opts . WantChecksum . Type . IsSet ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										userDefined [ hash . MinIOMultipartChecksum ]  =  opts . WantChecksum . Type . String ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										userDefined [ hash . MinIOMultipartChecksumType ]  =  opts . WantChecksum . Type . ObjType ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									modTime  :=  opts . MTime 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  opts . MTime . IsZero ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										modTime  =  UTCNow ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-09-12 01:22:12 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									onlineDisks ,  partsMetadata  =  shuffleDisksAndPartsMetadata ( onlineDisks ,  partsMetadata ,  fi ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-28 15:09:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Fill all the necessary metadata.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Update `xl.meta` content on each disks.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  index  :=  range  partsMetadata  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-11 02:12:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										partsMetadata [ index ] . Fresh  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										partsMetadata [ index ] . ModTime  =  modTime 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-05 19:14:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										partsMetadata [ index ] . Metadata  =  userDefined 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-18 00:40:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									uploadUUID  :=  fmt . Sprintf ( "%sx%d" ,  mustGetUUID ( ) ,  modTime . UnixNano ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-29 10:39:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									uploadID  :=  base64 . RawURLEncoding . EncodeToString ( fmt . Appendf ( nil ,  "%s.%s" ,  globalDeploymentID ( ) ,  uploadUUID ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-26 01:52:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									uploadIDPath  :=  er . getUploadIDDir ( bucket ,  object ,  uploadUUID ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Write updated `xl.meta` to all disks.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  _ ,  err  :=  writeAllMetadata ( ctx ,  onlineDisks ,  bucket ,  minioMetaMultipartBucket ,  uploadIDPath ,  partsMetadata ,  writeQuorum ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  toObjectErr ( err ,  bucket ,  object ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-10-25 08:37:18 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  & NewMultipartUploadResult { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										UploadID :      uploadID , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ChecksumAlgo :  userDefined [ hash . MinIOMultipartChecksum ] , 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ChecksumType :  userDefined [ hash . MinIOMultipartChecksumType ] , 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 07:43:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// NewMultipartUpload - initialize a new multipart upload, returns a
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// unique id. The unique id returned here is of UUID form, for each
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// subsequent request each UUID is unique.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Implements S3 compatible initiate multipart API.
  
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  NewMultipartUpload ( ctx  context . Context ,  bucket ,  object  string ,  opts  ObjectOptions )  ( * NewMultipartUploadResult ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! opts . NoAuditLog  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-14 06:22:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										auditObjectErasureSet ( ctx ,  "NewMultipartUpload" ,  object ,  & er ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-04 15:45:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									return  er . newMultipartUpload ( ctx ,  bucket ,  object ,  opts ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 07:43:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-01-14 03:07:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// renamePart - renames multipart part to its relevant location under uploadID.
  
						 
					
						
							
								
									
										
										
										
											2025-04-25 13:41:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  renamePart ( ctx  context . Context ,  disks  [ ] StorageAPI ,  srcBucket ,  srcEntry ,  dstBucket ,  dstEntry  string ,  optsMeta  [ ] byte ,  writeQuorum  int ,  skipParent  string )  ( [ ] StorageAPI ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2024-09-24 19:26:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									paths  :=  [ ] string { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										dstEntry , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										dstEntry  +  ".meta" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// cleanup existing paths first across all drives.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									er . cleanupMultipartPath ( ctx ,  paths ... ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-01-14 03:07:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									g  :=  errgroup . WithNErrs ( len ( disks ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Rename file on all underlying storage disks.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  index  :=  range  disks  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										g . Go ( func ( )  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  disks [ index ]  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  errDiskNotFound 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2025-04-25 13:41:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  disks [ index ] . RenamePart ( ctx ,  srcBucket ,  srcEntry ,  dstBucket ,  dstEntry ,  optsMeta ,  skipParent ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-01-14 03:07:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} ,  index ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Wait for all renames to finish.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errs  :=  g . Wait ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  :=  reduceWriteQuorumErrs ( ctx ,  errs ,  objectOpIgnoredErrs ,  writeQuorum ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										er . cleanupMultipartPath ( ctx ,  paths ... ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// We can safely allow RenameFile errors up to len(er.getDisks()) - writeQuorum
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// otherwise return failure. Cleanup successful renames.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  evalDisks ( disks ,  errs ) ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-07-05 16:04:50 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// PutObjectPart - reads incoming stream and internally erasure codes
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// them. This call is similar to single put operation but it is part
  
						 
					
						
							
								
									
										
										
										
											2016-08-05 13:01:58 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// of the multipart transaction.
  
						 
					
						
							
								
									
										
										
										
											2016-07-05 16:04:50 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Implements S3 compatible Upload Part API.
  
						 
					
						
							
								
									
										
										
										
											2020-09-15 06:57:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  PutObjectPart ( ctx  context . Context ,  bucket ,  object ,  uploadID  string ,  partID  int ,  r  * PutObjReader ,  opts  ObjectOptions )  ( pi  PartInfo ,  err  error )  {  
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! opts . NoAuditLog  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-14 06:22:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										auditObjectErasureSet ( ctx ,  "PutObjectPart" ,  object ,  & er ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-04 15:45:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									data  :=  r . Reader 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Validate input data size and it can never be less than zero.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  data . Size ( )  <  - 1  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-04 20:04:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										bugLogIf ( ctx ,  errInvalidArgument ,  logger . ErrorKind ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  pi ,  toObjectErr ( errInvalidArgument ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-11-18 19:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									uploadIDPath  :=  er . getUploadIDDir ( bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Validates if upload ID exists.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-30 06:40:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fi ,  _ ,  err  :=  er . checkUploadIDExists ( ctx ,  bucket ,  object ,  uploadID ,  true ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-18 19:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  errors . Is ( err ,  errVolumeNotFound )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  pi ,  toObjectErr ( err ,  bucket ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-18 19:09:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  pi ,  toObjectErr ( err ,  bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									onlineDisks  :=  er . getDisks ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									writeQuorum  :=  fi . WriteQuorum ( er . defaultWQuorum ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-07-15 05:59:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  cs  :=  fi . Metadata [ hash . MinIOMultipartChecksum ] ;  cs  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  r . ContentCRCType ( ) . String ( )  !=  cs  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  pi ,  InvalidArgument { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												Bucket :  bucket , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												Object :  fi . Name , 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 10:53:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												Err :     fmt . Errorf ( "checksum missing, want %q, got %q" ,  cs ,  r . ContentCRCType ( ) . String ( ) ) , 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									onlineDisks  =  shuffleDisks ( onlineDisks ,  fi . Erasure . Distribution ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-27 10:55:48 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-07-12 08:24:49 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Need a unique name for the part being written in minioMetaBucket to
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// accommodate concurrent PutObjectPart requests
 
							 
						 
					
						
							
								
									
										
										
										
											2016-07-13 06:20:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-28 12:42:33 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									partSuffix  :=  fmt . Sprintf ( "part.%d" ,  partID ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-25 03:06:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Random UUID and timestamp for temporary part file.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									tmpPart  :=  fmt . Sprintf ( "%sx%d" ,  mustGetUUID ( ) ,  time . Now ( ) . UnixNano ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									tmpPartPath  :=  pathJoin ( tmpPart ,  partSuffix ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-10-20 13:52:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Delete the temporary object part. If PutObjectPart succeeds there would be nothing to delete.
 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-25 05:19:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-28 00:57:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  countOnlineDisks ( onlineDisks )  !=  len ( onlineDisks )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-01 23:00:02 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											er . deleteAll ( context . Background ( ) ,  minioMetaTmpBucket ,  tmpPart ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-25 05:19:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-11-27 05:20:21 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-23 07:07:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									erasure ,  err  :=  NewErasure ( ctx ,  fi . Erasure . DataBlocks ,  fi . Erasure . ParityBlocks ,  fi . Erasure . BlockSize ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-08-15 09:08:42 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  pi ,  toObjectErr ( err ,  bucket ,  object ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2018-02-16 09:45:57 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Fetch buffer for I/O, returns from the pool if not allocates a new one and returns.
 
							 
						 
					
						
							
								
									
										
										
										
											2018-06-14 02:55:12 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									var  buffer  [ ] byte 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									switch  size  :=  data . Size ( ) ;  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  size  ==  0 : 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-18 15:03:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										buffer  =  make ( [ ] byte ,  1 )  // Allocate at least a byte to reach EOF
 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-18 03:19:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									case  size  >=  fi . Erasure . BlockSize  ||  size  ==  - 1 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  int64 ( globalBytePoolCap . Load ( ) . Width ( ) )  <  fi . Erasure . BlockSize  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											buffer  =  make ( [ ] byte ,  fi . Erasure . BlockSize ,  2 * fi . Erasure . BlockSize ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-04 08:28:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-20 00:44:59 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											buffer  =  globalBytePoolCap . Load ( ) . Get ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											defer  globalBytePoolCap . Load ( ) . Put ( buffer ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-04 08:28:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									case  size  <  fi . Erasure . BlockSize : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// No need to allocate fully fi.Erasure.BlockSize buffer if the incoming data is smaller.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										buffer  =  make ( [ ] byte ,  size ,  2 * size + int64 ( fi . Erasure . ParityBlocks + fi . Erasure . DataBlocks - 1 ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-06-14 02:55:12 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2018-02-16 09:45:57 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  len ( buffer )  >  int ( fi . Erasure . BlockSize )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										buffer  =  buffer [ : fi . Erasure . BlockSize ] 
							 
						 
					
						
							
								
									
										
										
										
											2018-08-07 06:14:08 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 20:58:18 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									writers  :=  make ( [ ] io . Writer ,  len ( onlineDisks ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-08-07 06:14:08 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									for  i ,  disk  :=  range  onlineDisks  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  disk  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										writers [ i ]  =  newBitrotWriter ( disk ,  bucket ,  minioMetaTmpBucket ,  tmpPartPath ,  erasure . ShardFileSize ( data . Size ( ) ) ,  DefaultBitrotAlgorithm ,  erasure . ShardSize ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-08-07 06:14:08 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2018-11-27 05:20:21 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-01-15 02:01:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									toEncode  :=  io . Reader ( data ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  data . Size ( )  >  bigFileThreshold  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Add input readahead.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// We use 2 buffers, so we always have a full buffer of input.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-20 00:44:59 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										pool  :=  globalBytePoolCap . Load ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										bufA  :=  pool . Get ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										bufB  :=  pool . Get ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										defer  pool . Put ( bufA ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										defer  pool . Put ( bufB ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-01-15 02:01:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ra ,  err  :=  readahead . NewReaderBuffer ( data ,  [ ] [ ] byte { bufA [ : fi . Erasure . BlockSize ] ,  bufB [ : fi . Erasure . BlockSize ] } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											toEncode  =  ra 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											defer  ra . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-23 07:07:14 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									n ,  err  :=  erasure . Encode ( ctx ,  toEncode ,  writers ,  buffer ,  writeQuorum ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-27 03:26:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									closeErrs  :=  closeBitrotWriters ( writers ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-07-19 10:06:48 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-22 10:53:09 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  pi ,  toObjectErr ( err ,  bucket ,  object ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-07-19 10:06:48 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-27 03:26:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  closeErr  :=  reduceWriteQuorumErrs ( ctx ,  closeErrs ,  objectOpIgnoredErrs ,  writeQuorum ) ;  closeErr  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  pi ,  toObjectErr ( closeErr ,  bucket ,  object ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2016-10-20 13:52:03 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-07-19 10:06:48 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Should return IncompleteBody{} error when reader has fewer bytes
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// than specified in request header.
 
							 
						 
					
						
							
								
									
										
										
										
											2018-08-07 06:14:08 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  n  <  data . Size ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-09 05:22:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  pi ,  IncompleteBody { Bucket :  bucket ,  Object :  object } 
							 
						 
					
						
							
								
									
										
										
										
											2016-07-19 10:06:48 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2016-07-02 05:33:28 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-08-07 06:14:08 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									for  i  :=  range  writers  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  writers [ i ]  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											onlineDisks [ i ]  =  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-05-30 06:38:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Rename temporary part file to its final location.
 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									partPath  :=  pathJoin ( uploadIDPath ,  fi . DataDir ,  partSuffix ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-26 18:15:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-11-15 09:36:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									md5hex  :=  r . MD5CurrentHexString ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-17 10:35:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  opts . PreserveETag  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										md5hex  =  opts . PreserveETag 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-07-12 08:30:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  index  [ ] byte 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  opts . IndexCB  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										index  =  opts . IndexCB ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-22 13:30:34 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-12 02:35:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									actualSize  :=  data . ActualSize ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  actualSize  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										_ ,  encrypted  :=  crypto . IsEncrypted ( fi . Metadata ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										compressed  :=  fi . IsCompressed ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										switch  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  compressed : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// ... nothing changes for compressed stream.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-12 20:24:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											// if actualSize is -1 we have no known way to
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// determine what is the actualSize.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-12 02:35:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										case  encrypted : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											decSize ,  err  :=  sio . DecryptedSize ( uint64 ( n ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												actualSize  =  int64 ( decSize ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											actualSize  =  n 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									partInfo  :=  ObjectPartInfo { 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-20 09:56:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										Number :      partID , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ETag :        md5hex , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Size :        n , 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-12 02:35:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ActualSize :  actualSize , 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-20 09:56:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ModTime :     UTCNow ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Index :       index , 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										Checksums :   r . ContentCRC ( ) , 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-20 09:56:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-06 10:53:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									partFI ,  err  :=  partInfo . MarshalMsg ( nil ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  pi ,  toObjectErr ( err ,  minioMetaMultipartBucket ,  partPath ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-01 11:23:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-30 06:40:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Serialize concurrent part uploads.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-12 02:35:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									partIDLock  :=  er . NewNSLock ( bucket ,  pathJoin ( object ,  uploadID ,  strconv . Itoa ( partID ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									plkctx ,  err  :=  partIDLock . GetLock ( ctx ,  globalOperationTimeout ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  PartInfo { } ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ctx  =  plkctx . Context ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  partIDLock . Unlock ( plkctx ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-14 05:36:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Read lock for upload id, only held while reading the upload metadata.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									uploadIDRLock  :=  er . NewNSLock ( bucket ,  pathJoin ( object ,  uploadID ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									rlkctx ,  err  :=  uploadIDRLock . GetRLock ( ctx ,  globalOperationTimeout ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  PartInfo { } ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ctx  =  rlkctx . Context ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  uploadIDRLock . RUnlock ( rlkctx ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-04-25 13:41:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									onlineDisks ,  err  =  er . renamePart ( ctx ,  onlineDisks ,  minioMetaTmpBucket ,  tmpPartPath ,  minioMetaMultipartBucket ,  partPath ,  partFI ,  writeQuorum ,  uploadIDPath ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-04-25 13:41:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  errors . Is ( err ,  errUploadIDNotFound )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  pi ,  toObjectErr ( errUploadIDNotFound ,  bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  errors . Is ( err ,  errFileNotFound )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// An in-quorum errFileNotFound means that client stream
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// prematurely closed and we do not find any xl.meta or
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// part.1's - in such a scenario we must return as if client
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// disconnected. This means that erasure.Encode() CreateFile()
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// did not do anything.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  pi ,  IncompleteBody { Bucket :  bucket ,  Object :  object } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  pi ,  toObjectErr ( err ,  minioMetaMultipartBucket ,  partPath ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-02-01 01:38:34 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-05-29 06:13:15 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Return success.
 
							 
						 
					
						
							
								
									
										
										
										
											2017-02-01 01:38:34 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									return  PartInfo { 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										PartNumber :         partInfo . Number , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ETag :               partInfo . ETag , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										LastModified :       partInfo . ModTime , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Size :               partInfo . Size , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ActualSize :         partInfo . ActualSize , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ChecksumCRC32 :      partInfo . Checksums [ "CRC32" ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ChecksumCRC32C :     partInfo . Checksums [ "CRC32C" ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ChecksumSHA1 :       partInfo . Checksums [ "SHA1" ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ChecksumSHA256 :     partInfo . Checksums [ "SHA256" ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ChecksumCRC64NVME :  partInfo . Checksums [ "CRC64NVME" ] , 
							 
						 
					
						
							
								
									
										
										
										
											2017-02-01 01:38:34 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-29 03:36:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// GetMultipartInfo returns multipart metadata uploaded during newMultipartUpload, used
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// by callers to verify object states
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// - encrypted
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// - compressed
  
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// Does not contain currently uploaded parts by design.
  
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  GetMultipartInfo ( ctx  context . Context ,  bucket ,  object ,  uploadID  string ,  opts  ObjectOptions )  ( MultipartInfo ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! opts . NoAuditLog  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-14 06:22:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										auditObjectErasureSet ( ctx ,  "GetMultipartInfo" ,  object ,  & er ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-04 15:45:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-29 03:36:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									result  :=  MultipartInfo { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Bucket :    bucket , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Object :    object , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										UploadID :  uploadID , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fi ,  _ ,  err  :=  er . checkUploadIDExists ( ctx ,  bucket ,  object ,  uploadID ,  false ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-29 03:36:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  errors . Is ( err ,  errVolumeNotFound )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  result ,  toObjectErr ( err ,  bucket ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  result ,  toObjectErr ( err ,  bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-29 03:36:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-09-11 02:37:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									result . UserDefined  =  cloneMSS ( fi . Metadata ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-29 03:36:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									return  result ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  listParts ( ctx  context . Context ,  onlineDisks  [ ] StorageAPI ,  partPath  string ,  readQuorum  int )  ( [ ] int ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									g  :=  errgroup . WithNErrs ( len ( onlineDisks ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									objectParts  :=  make ( [ ] [ ] string ,  len ( onlineDisks ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// List uploaded parts from drives.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  index  :=  range  onlineDisks  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										g . Go ( func ( )  ( err  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  onlineDisks [ index ]  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  errDiskNotFound 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											objectParts [ index ] ,  err  =  onlineDisks [ index ] . ListDir ( ctx ,  minioMetaMultipartBucket ,  minioMetaMultipartBucket ,  partPath ,  - 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} ,  index ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  reduceReadQuorumErrs ( ctx ,  g . Wait ( ) ,  objectOpIgnoredErrs ,  readQuorum ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									partQuorumMap  :=  make ( map [ int ] int ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  driveParts  :=  range  objectParts  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										partsWithMetaCount  :=  make ( map [ int ] int ,  len ( driveParts ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// part files can be either part.N or part.N.meta
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  partPath  :=  range  driveParts  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											var  partNum  int 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  _ ,  err  :=  fmt . Sscanf ( partPath ,  "part.%d" ,  & partNum ) ;  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												partsWithMetaCount [ partNum ] ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  _ ,  err  :=  fmt . Sscanf ( partPath ,  "part.%d.meta" ,  & partNum ) ;  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												partsWithMetaCount [ partNum ] ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Include only part.N.meta files with corresponding part.N
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  partNum ,  cnt  :=  range  partsWithMetaCount  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  cnt  <  2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											partQuorumMap [ partNum ] ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  partNums  [ ] int 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  partNum ,  count  :=  range  partQuorumMap  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  count  <  readQuorum  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										partNums  =  append ( partNums ,  partNum ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sort . Ints ( partNums ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  partNums ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-03-16 04:55:23 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// ListObjectParts - lists all previously uploaded parts for a given
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// object and uploadID.  Takes additional input of part-number-marker
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// to indicate where the listing should begin from.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Implements S3 compatible ListObjectParts API. The resulting
  
						 
					
						
							
								
									
										
										
										
											2018-06-29 07:02:02 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// ListPartsInfo structure is marshaled directly into XML and
  
						 
					
						
							
								
									
										
										
										
											2018-03-16 04:55:23 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// replied back to the client.
  
						 
					
						
							
								
									
										
										
										
											2021-03-04 10:36:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  ListObjectParts ( ctx  context . Context ,  bucket ,  object ,  uploadID  string ,  partNumberMarker ,  maxParts  int ,  opts  ObjectOptions )  ( result  ListPartsInfo ,  err  error )  {  
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! opts . NoAuditLog  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-14 06:22:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										auditObjectErasureSet ( ctx ,  "ListObjectParts" ,  object ,  & er ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-04 15:45:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fi ,  _ ,  err  :=  er . checkUploadIDExists ( ctx ,  bucket ,  object ,  uploadID ,  false ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-04-24 05:54:28 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  result ,  toObjectErr ( err ,  bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-16 04:55:23 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									uploadIDPath  :=  er . getUploadIDDir ( bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  partNumberMarker  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										partNumberMarker  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Limit output to maxPartsList.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  maxParts  >  maxPartsList  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										maxParts  =  maxPartsList 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-01 11:23:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-10-25 04:51:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Populate the result stub.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result . Bucket  =  bucket 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result . Object  =  object 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result . UploadID  =  uploadID 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result . MaxParts  =  maxParts 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result . PartNumberMarker  =  partNumberMarker 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result . UserDefined  =  cloneMSS ( fi . Metadata ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result . ChecksumAlgorithm  =  fi . Metadata [ hash . MinIOMultipartChecksum ] 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									result . ChecksumType  =  fi . Metadata [ hash . MinIOMultipartChecksumType ] 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-22 07:47:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-10-25 04:51:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  maxParts  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  result ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									onlineDisks  :=  er . getDisks ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									readQuorum  :=  fi . ReadQuorum ( er . defaultRQuorum ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Read Part info for all parts
 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									partPath  :=  pathJoin ( uploadIDPath ,  fi . DataDir )  +  SlashSeparator 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// List parts in quorum
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									partNums ,  err  :=  er . listParts ( ctx ,  onlineDisks ,  partPath ,  readQuorum ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// This means that fi.DataDir, is not yet populated so we
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// return an empty response.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  errors . Is ( err ,  errFileNotFound )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  result ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  result ,  toObjectErr ( err ,  bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  len ( partNums )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  result ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									start  :=  objectPartIndexNums ( partNums ,  partNumberMarker ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-04-04 21:15:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  partNumberMarker  >  0  &&  start  ==  - 1  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Marker not present among what is present on the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// server, we return an empty list.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  result ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  partNumberMarker  >  0  &&  start  !=  - 1  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  start + 1  >=  len ( partNums )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Marker indicates that we are the end
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// of the list, so we simply return empty
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  result ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										partNums  =  partNums [ start + 1 : ] 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 12:24:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									result . Parts  =  make ( [ ] PartInfo ,  0 ,  len ( partNums ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									partMetaPaths  :=  make ( [ ] string ,  len ( partNums ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i ,  part  :=  range  partNums  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										partMetaPaths [ i ]  =  pathJoin ( partPath ,  fmt . Sprintf ( "part.%d.meta" ,  part ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-25 14:33:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Read parts in quorum
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									objParts ,  err  :=  readParts ( ctx ,  onlineDisks ,  minioMetaMultipartBucket ,  partMetaPaths , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										partNums ,  readQuorum ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  result ,  toObjectErr ( err ,  bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									count  :=  maxParts 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  objPart  :=  range  objParts  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-02-01 01:38:34 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										result . Parts  =  append ( result . Parts ,  PartInfo { 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											PartNumber :         objPart . Number , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											LastModified :       objPart . ModTime , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ETag :               objPart . ETag , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Size :               objPart . Size , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ActualSize :         objPart . ActualSize , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ChecksumCRC32 :      objPart . Checksums [ "CRC32" ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ChecksumCRC32C :     objPart . Checksums [ "CRC32C" ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ChecksumSHA1 :       objPart . Checksums [ "SHA1" ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ChecksumSHA256 :     objPart . Checksums [ "SHA256" ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ChecksumCRC64NVME :  objPart . Checksums [ "CRC64NVME" ] , 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										count -- 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  count  ==  0  { 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-22 07:47:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  len ( objParts )  >  len ( result . Parts )  { 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										result . IsTruncated  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Make sure to fill next part number marker if IsTruncated is true for subsequent listing.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										result . NextPartNumberMarker  =  result . Parts [ len ( result . Parts ) - 1 ] . PartNumber 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									return  result ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  readParts ( ctx  context . Context ,  disks  [ ] StorageAPI ,  bucket  string ,  partMetaPaths  [ ] string ,  partNumbers  [ ] int ,  readQuorum  int )  ( [ ] ObjectPartInfo ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									g  :=  errgroup . WithNErrs ( len ( disks ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									objectPartInfos  :=  make ( [ ] [ ] * ObjectPartInfo ,  len ( disks ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Rename file on all underlying storage disks.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  index  :=  range  disks  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										g . Go ( func ( )  ( err  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  disks [ index ]  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  errDiskNotFound 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											objectPartInfos [ index ] ,  err  =  disks [ index ] . ReadParts ( ctx ,  bucket ,  partMetaPaths ... ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} ,  index ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  reduceReadQuorumErrs ( ctx ,  g . Wait ( ) ,  objectOpIgnoredErrs ,  readQuorum ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 17:42:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									partInfosInQuorum  :=  make ( [ ] ObjectPartInfo ,  len ( partMetaPaths ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  pidx  :=  range  partMetaPaths  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// partMetaQuorumMap uses
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										//  - path/to/part.N as key to collate errors from failed drives.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										//  - part ETag to collate part metadata
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										partMetaQuorumMap  :=  make ( map [ string ] int ,  len ( partNumbers ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										var  pinfos  [ ] * ObjectPartInfo 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  idx  :=  range  disks  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  len ( objectPartInfos [ idx ] )  !=  len ( partMetaPaths )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												partMetaQuorumMap [ partMetaPaths [ pidx ] ] ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											pinfo  :=  objectPartInfos [ idx ] [ pidx ] 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  pinfo  !=  nil  &&  pinfo . ETag  !=  ""  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												pinfos  =  append ( pinfos ,  pinfo ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												partMetaQuorumMap [ pinfo . ETag ] ++ 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											partMetaQuorumMap [ partMetaPaths [ pidx ] ] ++ 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  maxQuorum  int 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  maxETag  string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  maxPartMeta  string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  etag ,  quorum  :=  range  partMetaQuorumMap  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  maxQuorum  <  quorum  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												maxQuorum  =  quorum 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												maxETag  =  etag 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												maxPartMeta  =  etag 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// found is a representative ObjectPartInfo which either has the maximally occurring ETag or an error.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  found  * ObjectPartInfo 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  pinfo  :=  range  pinfos  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  pinfo  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  maxETag  !=  ""  &&  pinfo . ETag  ==  maxETag  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												found  =  pinfo 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  pinfo . ETag  ==  ""  &&  maxPartMeta  !=  ""  &&  path . Base ( maxPartMeta )  ==  fmt . Sprintf ( "part.%d.meta" ,  pinfo . Number )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												found  =  pinfo 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  found  !=  nil  &&  found . ETag  !=  ""  &&  partMetaQuorumMap [ maxETag ]  >=  readQuorum  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											partInfosInQuorum [ pidx ]  =  * found 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										partInfosInQuorum [ pidx ]  =  ObjectPartInfo { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Number :  partNumbers [ pidx ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Error :  InvalidPart { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												PartNumber :  partNumbers [ pidx ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} . Error ( ) , 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  partInfosInQuorum ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  objPartToPartErr ( part  ObjectPartInfo )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  strings . Contains ( part . Error ,  "file not found" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  InvalidPart { PartNumber :  part . Number } 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  strings . Contains ( part . Error ,  "Specified part could not be found" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  InvalidPart { PartNumber :  part . Number } 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  strings . Contains ( part . Error ,  errErasureReadQuorum . Error ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  errErasureReadQuorum 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  errors . New ( part . Error ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 07:43:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// CompleteMultipartUpload - completes an ongoing multipart
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// transaction after receiving all the parts indicated by the client.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Returns an md5sum calculated by concatenating all the individual
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// md5sums of all the parts.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Implements S3 compatible Complete multipart API.
  
						 
					
						
							
								
									
										
										
										
											2020-09-15 06:57:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  CompleteMultipartUpload ( ctx  context . Context ,  bucket  string ,  object  string ,  uploadID  string ,  parts  [ ] CompletePart ,  opts  ObjectOptions )  ( oi  ObjectInfo ,  err  error )  {  
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! opts . NoAuditLog  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-14 06:22:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										auditObjectErasureSet ( ctx ,  "CompleteMultipartUpload" ,  object ,  & er ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-04 15:45:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-11 08:31:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  opts . CheckPrecondFn  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! opts . NoLock  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ns  :=  er . NewNSLock ( bucket ,  object ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											lkctx ,  err  :=  ns . GetLock ( ctx ,  globalOperationTimeout ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  ObjectInfo { } ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ctx  =  lkctx . Context ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											defer  ns . Unlock ( lkctx ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											opts . NoLock  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										obj ,  err  :=  er . getObjectInfo ( ctx ,  bucket ,  object ,  opts ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  ==  nil  &&  opts . CheckPrecondFn ( obj )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  ObjectInfo { } ,  PreConditionFailed { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  &&  ! isErrVersionNotFound ( err )  &&  ! isErrObjectNotFound ( err )  &&  ! isErrReadQuorum ( err )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  ObjectInfo { } ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 00:13:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-09 01:43:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// if object doesn't exist return error for If-Match conditional requests
 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 00:13:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// If-None-Match should be allowed to proceed for non-existent objects
 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-09 01:43:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  err  !=  nil  &&  opts . HasIfMatch  &&  ( isErrObjectNotFound ( err )  ||  isErrVersionNotFound ( err ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 00:13:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  ObjectInfo { } ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-11 08:31:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-18 00:37:55 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fi ,  partsMetadata ,  err  :=  er . checkUploadIDExists ( ctx ,  bucket ,  object ,  uploadID ,  true ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-31 04:43:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  errors . Is ( err ,  errVolumeNotFound )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  oi ,  toObjectErr ( err ,  bucket ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2019-04-24 05:54:28 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  oi ,  toObjectErr ( err ,  bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-28 12:50:09 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-02-22 11:43:44 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									uploadIDPath  :=  er . getUploadIDDir ( bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-16 03:43:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									onlineDisks  :=  er . getDisks ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									writeQuorum  :=  fi . WriteQuorum ( er . defaultWQuorum ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									readQuorum  :=  fi . ReadQuorum ( er . defaultRQuorum ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Read Part info for all parts
 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 04:37:19 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									partPath  :=  pathJoin ( uploadIDPath ,  fi . DataDir )  +  SlashSeparator 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									partMetaPaths  :=  make ( [ ] string ,  len ( parts ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									partNumbers  :=  make ( [ ] int ,  len ( parts ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  idx ,  part  :=  range  parts  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										partMetaPaths [ idx ]  =  pathJoin ( partPath ,  fmt . Sprintf ( "part.%d.meta" ,  part . PartNumber ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										partNumbers [ idx ]  =  part . PartNumber 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									partInfoFiles ,  err  :=  readParts ( ctx ,  onlineDisks ,  minioMetaMultipartBucket ,  partMetaPaths ,  partNumbers ,  readQuorum ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 10:06:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  oi ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  len ( partInfoFiles )  !=  len ( parts )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Should only happen through internal error
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										err  :=  fmt . Errorf ( "unexpected part result count: %d, want %d" ,  len ( partInfoFiles ) ,  len ( parts ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-04 20:04:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										bugLogIf ( ctx ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  oi ,  toObjectErr ( err ,  bucket ,  object ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Checksum type set when upload started.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  checksumType  hash . ChecksumType 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  cs  :=  fi . Metadata [ hash . MinIOMultipartChecksum ] ;  cs  !=  ""  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										checksumType  =  hash . NewChecksumType ( cs ,  fi . Metadata [ hash . MinIOMultipartChecksumType ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  opts . WantChecksum  !=  nil  &&  ! opts . WantChecksum . Type . Is ( checksumType )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  oi ,  InvalidArgument { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												Bucket :  bucket , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												Object :  fi . Name , 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												Err :     fmt . Errorf ( "checksum type mismatch. got %q (%s) expected %q (%s)" ,  checksumType . String ( ) ,  checksumType . ObjType ( ) ,  opts . WantChecksum . Type . String ( ) ,  opts . WantChecksum . Type . ObjType ( ) ) , 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-22 22:15:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										checksumType  |=  hash . ChecksumMultipart  |  hash . ChecksumIncludesMultipart 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  checksumCombined  [ ] byte 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// However, in case of encryption, the persisted part ETags don't match
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// what we have sent to the client during PutObjectPart. The reason is
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// that ETags are encrypted. Hence, the client will send a list of complete
 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-12 02:35:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// part ETags of which may not match the ETag of any part. For example
 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									//   ETag (client):          30902184f4e62dd8f98f0aaff810c626
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//   ETag (server-internal): 20000f00ce5dc16e3f3b124f586ae1d88e9caa1c598415c2759bbb50e84a59f630902184f4e62dd8f98f0aaff810c626
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Therefore, we adjust all ETags sent by the client to match what is stored
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// on the backend.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-08 02:18:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									kind ,  _  :=  crypto . IsEncrypted ( fi . Metadata ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  objectEncryptionKey  [ ] byte 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-08 02:18:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									switch  kind  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  crypto . SSEC : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  checksumType . IsSet ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  opts . EncryptFn  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  oi ,  crypto . ErrMissingCustomerKey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											baseKey  :=  opts . EncryptFn ( "" ,  nil ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  len ( baseKey )  !=  32  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  oi ,  crypto . ErrInvalidCustomerKey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											objectEncryptionKey ,  err  =  decryptObjectMeta ( baseKey ,  bucket ,  object ,  fi . Metadata ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  oi ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  crypto . S3 ,  crypto . S3KMS : 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										objectEncryptionKey ,  err  =  decryptObjectMeta ( nil ,  bucket ,  object ,  fi . Metadata ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  oi ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-08 02:18:18 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  len ( objectEncryptionKey )  ==  32  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  key  crypto . ObjectKey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										copy ( key [ : ] ,  objectEncryptionKey ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										opts . EncryptFn  =  metadataEncrypter ( key ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  idx ,  part  :=  range  partInfoFiles  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  part . Error  !=  ""  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-06 18:51:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											err  =  objPartToPartErr ( part ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-04 20:04:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											bugLogIf ( ctx ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  oi ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-20 09:56:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  parts [ idx ] . PartNumber  !=  part . Number  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											internalLogIf ( ctx ,  fmt . Errorf ( "part.%d.meta has incorrect corresponding part number: expected %d, got %d" ,  parts [ idx ] . PartNumber ,  parts [ idx ] . PartNumber ,  part . Number ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  oi ,  InvalidPart { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												PartNumber :  part . Number , 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-20 09:56:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Add the current part.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-12 16:38:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										fi . AddObjectPart ( part . Number ,  part . ETag ,  part . Size ,  part . ActualSize ,  part . ModTime ,  part . Index ,  part . Checksums ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2016-07-15 05:59:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-01 11:23:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Calculate full object size.
 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									var  objectSize  int64 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 12:24:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-09-28 11:36:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Calculate consolidated actual size.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  objectActualSize  int64 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-07-28 02:57:08 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Order online disks in accordance with distribution order.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Order parts metadata in accordance with distribution order.
 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-16 11:03:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									onlineDisks ,  partsMetadata  =  shuffleDisksAndPartsMetadataByIndex ( onlineDisks ,  partsMetadata ,  fi ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-07-28 02:57:08 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Save current erasure metadata for validation.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-01-03 01:15:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									currentFI  :=  fi 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 12:24:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Allocate parts similar to incoming slice.
 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									fi . Parts  =  make ( [ ] ObjectPartInfo ,  len ( parts ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 12:24:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  checksum  hash . Checksum 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									checksum . Type  =  checksumType 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 07:43:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Validate each part and then commit to disk.
 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									for  i ,  part  :=  range  parts  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										partIdx  :=  objectPartIndex ( currentFI . Parts ,  part . PartNumber ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-20 05:51:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										// All parts should have same part number.
 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 12:24:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										if  partIdx  ==  - 1  { 
							 
						 
					
						
							
								
									
										
										
										
											2018-08-15 09:35:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											invp  :=  InvalidPart { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												PartNumber :  part . PartNumber , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												GotETag :     part . ETag , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  oi ,  invp 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										expPart  :=  currentFI . Parts [ partIdx ] 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-20 05:51:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										// ensure that part ETag is canonicalized to strip off extraneous quotes
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										part . ETag  =  canonicalizeETag ( part . ETag ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-06 04:08:51 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										expETag  :=  tryDecryptETag ( objectEncryptionKey ,  expPart . ETag ,  kind  ==  crypto . S3 ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  expETag  !=  part . ETag  { 
							 
						 
					
						
							
								
									
										
										
										
											2018-08-15 09:35:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											invp  :=  InvalidPart { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												PartNumber :  part . PartNumber , 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												ExpETag :     expETag , 
							 
						 
					
						
							
								
									
										
										
										
											2018-08-15 09:35:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												GotETag :     part . ETag , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  oi ,  invp 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 12:24:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-20 05:51:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  checksumType . IsSet ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											crc  :=  expPart . Checksums [ checksumType . String ( ) ] 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  crc  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  oi ,  InvalidPart { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													PartNumber :  part . PartNumber , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											wantCS  :=  map [ string ] string { 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												hash . ChecksumCRC32 . String ( ) :      part . ChecksumCRC32 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												hash . ChecksumCRC32C . String ( ) :     part . ChecksumCRC32C , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												hash . ChecksumSHA1 . String ( ) :       part . ChecksumSHA1 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												hash . ChecksumSHA256 . String ( ) :     part . ChecksumSHA256 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												hash . ChecksumCRC64NVME . String ( ) :  part . ChecksumCRC64NVME , 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  wantCS [ checksumType . String ( ) ]  !=  crc  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  oi ,  InvalidPart { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													PartNumber :  part . PartNumber , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													ExpETag :     wantCS [ checksumType . String ( ) ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													GotETag :     crc , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											cs  :=  hash . NewChecksumString ( checksumType . String ( ) ,  crc ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ! cs . Valid ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  oi ,  InvalidPart { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													PartNumber :  part . PartNumber , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  checksumType . FullObjectRequested ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  err  :=  checksum . AddPart ( * cs ,  expPart . ActualSize ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													return  oi ,  InvalidPart { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														PartNumber :  part . PartNumber , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														ExpETag :     "<nil>" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														GotETag :     err . Error ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-16 02:58:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											checksumCombined  =  append ( checksumCombined ,  cs . Raw ... ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// All parts except the last part has to be at least 5MB.
 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										if  ( i  <  len ( parts ) - 1 )  &&  ! isMinAllowedPartSize ( currentFI . Parts [ partIdx ] . ActualSize )  { 
							 
						 
					
						
							
								
									
										
										
										
											2018-04-06 06:04:40 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											return  oi ,  PartTooSmall { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												PartNumber :  part . PartNumber , 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												PartSize :    expPart . ActualSize , 
							 
						 
					
						
							
								
									
										
										
										
											2018-04-06 06:04:40 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												PartETag :    part . ETag , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 12:24:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Save for total object size.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										objectSize  +=  expPart . Size 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 12:24:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-09-28 11:36:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										// Save the consolidated actual size.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										objectActualSize  +=  expPart . ActualSize 
							 
						 
					
						
							
								
									
										
										
										
											2018-09-28 11:36:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 12:24:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										// Add incoming parts.
 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										fi . Parts [ i ]  =  ObjectPartInfo { 
							 
						 
					
						
							
								
									
										
										
										
											2018-09-28 11:36:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											Number :      part . PartNumber , 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-24 12:17:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											Size :        expPart . Size , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ActualSize :  expPart . ActualSize , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ModTime :     expPart . ModTime , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Index :       expPart . Index , 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											Checksums :   nil ,  // Not transferred since we do not need it.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  opts . WantChecksum  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  checksumType . FullObjectRequested ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  opts . WantChecksum . Encoded  !=  checksum . Encoded  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												err  :=  hash . ChecksumMismatch { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													Want :  opts . WantChecksum . Encoded , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													Got :   checksum . Encoded , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  oi ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											err  :=  opts . WantChecksum . Matches ( checksumCombined ,  len ( parts ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  oi ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-25 12:24:20 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-21 10:28:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-06-13 14:56:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Accept encrypted checksum from incoming request.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  opts . UserDefined [ ReplicationSsecChecksumHeader ]  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  v ,  err  :=  base64 . StdEncoding . DecodeString ( opts . UserDefined [ ReplicationSsecChecksumHeader ] ) ;  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fi . Checksum  =  v 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										delete ( opts . UserDefined ,  ReplicationSsecChecksumHeader ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  checksumType . IsSet ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-04-28 23:26:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										checksumType  |=  hash . ChecksumMultipart  |  hash . ChecksumIncludesMultipart 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										checksum . Type  =  checksumType 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! checksumType . FullObjectRequested ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											checksum  =  * hash . NewChecksumFromData ( checksumType ,  checksumCombined ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fi . Checksum  =  checksum . AppendTo ( nil ,  checksumCombined ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-31 23:13:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  opts . EncryptFn  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fi . Checksum  =  opts . EncryptFn ( "object-checksum" ,  fi . Checksum ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-30 07:57:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-20 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Remove superfluous internal headers.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									delete ( fi . Metadata ,  hash . MinIOMultipartChecksum ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									delete ( fi . Metadata ,  hash . MinIOMultipartChecksumType ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Save the final object size and modtime.
 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									fi . Size  =  objectSize 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-09 08:36:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fi . ModTime  =  opts . MTime 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  opts . MTime . IsZero ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fi . ModTime  =  UTCNow ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Save successfully calculated md5sum.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-27 06:43:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// for replica, newMultipartUpload would have already sent the replication ETag
 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-09 13:25:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  fi . Metadata [ "etag" ]  ==  ""  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-27 06:43:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  opts . UserDefined [ "etag" ]  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fi . Metadata [ "etag" ]  =  opts . UserDefined [ "etag" ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  {  // fallback if not already calculated in handler.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fi . Metadata [ "etag" ]  =  getCompleteMultipartMD5 ( parts ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-08-13 08:32:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-22 13:30:34 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-09-28 11:36:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Save the consolidated actual size.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-29 01:44:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  opts . ReplicationRequest  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-08 23:29:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  v  :=  opts . UserDefined [ ReservedMetadataPrefix + "Actual-Object-Size" ] ;  v  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fi . Metadata [ ReservedMetadataPrefix + "actual-size" ]  =  v 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-29 01:44:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fi . Metadata [ ReservedMetadataPrefix + "actual-size" ]  =  strconv . FormatInt ( objectActualSize ,  10 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2018-09-28 11:36:17 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-02-04 06:03:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  opts . DataMovement  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fi . SetDataMov ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Update all erasure metadata, make sure to not modify fields like
 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-01 11:23:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// checksum which are different on each disks.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  index  :=  range  partsMetadata  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-21 01:10:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  partsMetadata [ index ] . IsValid ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											partsMetadata [ index ] . Size  =  fi . Size 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											partsMetadata [ index ] . ModTime  =  fi . ModTime 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											partsMetadata [ index ] . Metadata  =  fi . Metadata 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											partsMetadata [ index ] . Parts  =  fi . Parts 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-27 09:14:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											partsMetadata [ index ] . Checksum  =  fi . Checksum 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-28 00:57:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											partsMetadata [ index ] . Versioned  =  opts . Versioned  ||  opts . VersionSuspended 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-21 01:10:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2016-09-01 02:39:08 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									paths  :=  make ( [ ] string ,  0 ,  len ( currentFI . Parts ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-10 21:13:16 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Remove parts that weren't present in CompleteMultipartUpload request.
 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									for  _ ,  curpart  :=  range  currentFI . Parts  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										paths  =  append ( paths ,  pathJoin ( uploadIDPath ,  currentFI . DataDir ,  fmt . Sprintf ( "part.%d.meta" ,  curpart . Number ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-28 00:57:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										if  objectPartIndex ( fi . Parts ,  curpart . Number )  ==  - 1  { 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-29 04:23:08 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											// Delete the missing part files. e.g,
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Request 1: NewMultipart
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Request 2: PutObjectPart 1
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Request 3: PutObjectPart 2
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Request 4: CompleteMultipartUpload --part 2
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// N.B. 1st part is not present. This part should be removed from the storage.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											paths  =  append ( paths ,  pathJoin ( uploadIDPath ,  currentFI . DataDir ,  fmt . Sprintf ( "part.%d" ,  curpart . Number ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-29 04:23:08 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-09-14 04:26:02 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! opts . NoLock  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										lk  :=  er . NewNSLock ( bucket ,  object ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										lkctx ,  err  :=  lk . GetLock ( ctx ,  globalOperationTimeout ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  ObjectInfo { } ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ctx  =  lkctx . Context ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										defer  lk . Unlock ( lkctx ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-30 09:56:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									er . cleanupMultipartPath ( ctx ,  paths ... )  // cleanup all part.N.meta, and skipped part.N's before final rename().
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-30 01:28:19 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											er . deleteAll ( context . Background ( ) ,  minioMetaMultipartBucket ,  uploadIDPath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-19 23:35:29 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-05-29 15:42:09 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Rename the multipart object to final location.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-24 01:15:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									onlineDisks ,  versions ,  oldDataDir ,  err  :=  renameData ( ctx ,  onlineDisks ,  minioMetaMultipartBucket ,  uploadIDPath , 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-17 00:52:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										partsMetadata ,  bucket ,  object ,  writeQuorum ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-29 01:53:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  oi ,  toObjectErr ( err ,  bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-03 07:57:39 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-14 18:29:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  =  er . commitRenameDataDir ( ctx ,  bucket ,  object ,  oldDataDir ,  onlineDisks ,  writeQuorum ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-29 01:53:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  ObjectInfo { } ,  toObjectErr ( err ,  bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-04-24 01:15:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! opts . Speedtest  &&  len ( versions )  >  0  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-14 06:26:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										globalMRFState . addPartialOp ( PartialOperation { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Bucket :     bucket , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Object :     object , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Queued :     time . Now ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Versions :   versions , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											SetIndex :   er . setIndex , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											PoolIndex :  er . poolIndex , 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-25 10:31:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-17 00:52:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-04-24 01:15:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! opts . Speedtest  &&  len ( versions )  ==  0  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-05 03:13:50 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Check if there is any offline disk and add it to the MRF list
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  disk  :=  range  onlineDisks  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  disk  !=  nil  &&  disk . IsOnline ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											er . addPartial ( bucket ,  object ,  fi . VersionID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-16 10:30:32 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-05-27 23:19:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  i  :=  range  len ( onlineDisks )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-12-23 01:16:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  onlineDisks [ i ]  !=  nil  &&  onlineDisks [ i ] . IsOnline ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// Object info is the same in all disks, so we can pick
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// the first meta from online disk
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fi  =  partsMetadata [ i ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break 
							 
						 
					
						
							
								
									
										
										
										
											2020-06-13 11:04:01 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-09-23 10:17:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// we are adding a new version to this object under the namespace lock, so this is the latest version.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									fi . IsLatest  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-01-17 11:23:43 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Success, return object info.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-31 17:57:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  fi . ToObjectInfo ( bucket ,  object ,  opts . Versioned  ||  opts . VersionSuspended ) ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2016-05-21 11:48:47 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 07:43:31 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// AbortMultipartUpload - aborts an ongoing multipart operation
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// signified by the input uploadID. This is an atomic operation
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// doesn't require clients to initiate multiple such requests.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// All parts are purged from all disks and reference to the uploadID
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// would be removed from the system, rollback is not possible on this
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// operation.
  
						 
					
						
							
								
									
										
										
										
											2021-03-04 10:36:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( er  erasureObjects )  AbortMultipartUpload ( ctx  context . Context ,  bucket ,  object ,  uploadID  string ,  opts  ObjectOptions )  ( err  error )  {  
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! opts . NoAuditLog  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-08-14 06:22:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										auditObjectErasureSet ( ctx ,  "AbortMultipartUpload" ,  object ,  & er ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-06 19:43:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2022-05-04 15:45:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-03-16 04:55:23 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									// Cleanup all uploaded parts.
 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 14:57:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									defer  er . deleteAll ( ctx ,  minioMetaMultipartBucket ,  er . getUploadIDDir ( bucket ,  object ,  uploadID ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-16 04:55:23 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 14:57:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Validates if upload ID exists.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									_ ,  _ ,  err  =  er . checkUploadIDExists ( ctx ,  bucket ,  object ,  uploadID ,  false ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  toObjectErr ( err ,  bucket ,  object ,  uploadID ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-16 04:55:23 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}