github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/erasure-utils.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "context" 22 "encoding/base64" 23 "fmt" 24 "io" 25 "strings" 26 27 "github.com/klauspost/reedsolomon" 28 ) 29 30 // getDataBlockLen - get length of data blocks from encoded blocks. 31 func getDataBlockLen(enBlocks [][]byte, dataBlocks int) int { 32 size := 0 33 // Figure out the data block length. 34 for _, block := range enBlocks[:dataBlocks] { 35 size += len(block) 36 } 37 return size 38 } 39 40 // Writes all the data blocks from encoded blocks until requested 41 // outSize length. Provides a way to skip bytes until the offset. 42 func writeDataBlocks(ctx context.Context, dst io.Writer, enBlocks [][]byte, dataBlocks int, offset int64, length int64) (int64, error) { 43 // Offset and out size cannot be negative. 44 if offset < 0 || length < 0 { 45 return 0, errUnexpected 46 } 47 48 // Do we have enough blocks? 49 if len(enBlocks) < dataBlocks { 50 return 0, reedsolomon.ErrTooFewShards 51 } 52 53 // Do we have enough data? 54 if int64(getDataBlockLen(enBlocks, dataBlocks)) < length { 55 return 0, reedsolomon.ErrShortData 56 } 57 58 // Counter to decrement total left to write. 59 write := length 60 61 // Counter to increment total written. 62 var totalWritten int64 63 64 // Write all data blocks to dst. 65 for _, block := range enBlocks[:dataBlocks] { 66 // Skip blocks until we have reached our offset. 67 if offset >= int64(len(block)) { 68 // Decrement offset. 69 offset -= int64(len(block)) 70 continue 71 } 72 73 // Skip until offset. 74 block = block[offset:] 75 76 // Reset the offset for next iteration to read everything 77 // from subsequent blocks. 78 offset = 0 79 80 // We have written all the blocks, write the last remaining block. 81 if write < int64(len(block)) { 82 n, err := dst.Write(block[:write]) 83 if err != nil { 84 return 0, err 85 } 86 totalWritten += int64(n) 87 break 88 } 89 90 // Copy the block. 91 n, err := dst.Write(block) 92 if err != nil { 93 return 0, err 94 } 95 96 // Decrement output size. 97 write -= int64(n) 98 99 // Increment written. 100 totalWritten += int64(n) 101 } 102 103 // Success. 104 return totalWritten, nil 105 } 106 107 // returns deploymentID from uploadID 108 func getDeplIDFromUpload(uploadID string) (string, error) { 109 uploadBytes, err := base64.RawURLEncoding.DecodeString(uploadID) 110 if err != nil { 111 return "", fmt.Errorf("error parsing uploadID %s (%w)", uploadID, err) 112 } 113 slc := strings.SplitN(string(uploadBytes), ".", 2) 114 if len(slc) != 2 { 115 return "", fmt.Errorf("uploadID %s has incorrect format", uploadID) 116 } 117 return slc[0], nil 118 }