github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/storage-rest-server.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  	"bufio"
    22  	"context"
    23  	"encoding/binary"
    24  	"encoding/gob"
    25  	"encoding/hex"
    26  	"errors"
    27  	"fmt"
    28  	"io"
    29  	"net/http"
    30  	"os/user"
    31  	"path"
    32  	"runtime"
    33  	"runtime/debug"
    34  	"strconv"
    35  	"strings"
    36  	"sync"
    37  	"time"
    38  
    39  	"github.com/minio/minio/internal/grid"
    40  	"github.com/tinylib/msgp/msgp"
    41  
    42  	jwtreq "github.com/golang-jwt/jwt/v4/request"
    43  	"github.com/minio/madmin-go/v3"
    44  	"github.com/minio/minio/internal/config"
    45  	xhttp "github.com/minio/minio/internal/http"
    46  	xioutil "github.com/minio/minio/internal/ioutil"
    47  	xjwt "github.com/minio/minio/internal/jwt"
    48  	"github.com/minio/minio/internal/logger"
    49  	"github.com/minio/mux"
    50  	xnet "github.com/minio/pkg/v2/net"
    51  )
    52  
    53  var errDiskStale = errors.New("drive stale")
    54  
    55  // To abstract a disk over network.
    56  type storageRESTServer struct {
    57  	endpoint Endpoint
    58  }
    59  
    60  var (
    61  	storageCheckPartsRPC     = grid.NewSingleHandler[*CheckPartsHandlerParams, grid.NoPayload](grid.HandlerCheckParts, func() *CheckPartsHandlerParams { return &CheckPartsHandlerParams{} }, grid.NewNoPayload)
    62  	storageDeleteFileRPC     = grid.NewSingleHandler[*DeleteFileHandlerParams, grid.NoPayload](grid.HandlerDeleteFile, func() *DeleteFileHandlerParams { return &DeleteFileHandlerParams{} }, grid.NewNoPayload).AllowCallRequestPool(true)
    63  	storageDeleteVersionRPC  = grid.NewSingleHandler[*DeleteVersionHandlerParams, grid.NoPayload](grid.HandlerDeleteVersion, func() *DeleteVersionHandlerParams { return &DeleteVersionHandlerParams{} }, grid.NewNoPayload)
    64  	storageDiskInfoRPC       = grid.NewSingleHandler[*DiskInfoOptions, *DiskInfo](grid.HandlerDiskInfo, func() *DiskInfoOptions { return &DiskInfoOptions{} }, func() *DiskInfo { return &DiskInfo{} }).WithSharedResponse().AllowCallRequestPool(true)
    65  	storageNSScannerRPC      = grid.NewStream[*nsScannerOptions, grid.NoPayload, *nsScannerResp](grid.HandlerNSScanner, func() *nsScannerOptions { return &nsScannerOptions{} }, nil, func() *nsScannerResp { return &nsScannerResp{} })
    66  	storageReadAllRPC        = grid.NewSingleHandler[*ReadAllHandlerParams, *grid.Bytes](grid.HandlerReadAll, func() *ReadAllHandlerParams { return &ReadAllHandlerParams{} }, grid.NewBytes).AllowCallRequestPool(true)
    67  	storageWriteAllRPC       = grid.NewSingleHandler[*WriteAllHandlerParams, grid.NoPayload](grid.HandlerWriteAll, func() *WriteAllHandlerParams { return &WriteAllHandlerParams{} }, grid.NewNoPayload)
    68  	storageReadVersionRPC    = grid.NewSingleHandler[*grid.MSS, *FileInfo](grid.HandlerReadVersion, grid.NewMSS, func() *FileInfo { return &FileInfo{} })
    69  	storageReadXLRPC         = grid.NewSingleHandler[*grid.MSS, *RawFileInfo](grid.HandlerReadXL, grid.NewMSS, func() *RawFileInfo { return &RawFileInfo{} })
    70  	storageRenameDataRPC     = grid.NewSingleHandler[*RenameDataHandlerParams, *RenameDataResp](grid.HandlerRenameData, func() *RenameDataHandlerParams { return &RenameDataHandlerParams{} }, func() *RenameDataResp { return &RenameDataResp{} })
    71  	storageRenameFileRPC     = grid.NewSingleHandler[*RenameFileHandlerParams, grid.NoPayload](grid.HandlerRenameFile, func() *RenameFileHandlerParams { return &RenameFileHandlerParams{} }, grid.NewNoPayload).AllowCallRequestPool(true)
    72  	storageStatVolRPC        = grid.NewSingleHandler[*grid.MSS, *VolInfo](grid.HandlerStatVol, grid.NewMSS, func() *VolInfo { return &VolInfo{} })
    73  	storageUpdateMetadataRPC = grid.NewSingleHandler[*MetadataHandlerParams, grid.NoPayload](grid.HandlerUpdateMetadata, func() *MetadataHandlerParams { return &MetadataHandlerParams{} }, grid.NewNoPayload)
    74  	storageWriteMetadataRPC  = grid.NewSingleHandler[*MetadataHandlerParams, grid.NoPayload](grid.HandlerWriteMetadata, func() *MetadataHandlerParams { return &MetadataHandlerParams{} }, grid.NewNoPayload)
    75  	storageListDirRPC        = grid.NewStream[*grid.MSS, grid.NoPayload, *ListDirResult](grid.HandlerListDir, grid.NewMSS, nil, func() *ListDirResult { return &ListDirResult{} }).WithOutCapacity(1)
    76  )
    77  
    78  func getStorageViaEndpoint(endpoint Endpoint) StorageAPI {
    79  	globalLocalDrivesMu.RLock()
    80  	defer globalLocalDrivesMu.RUnlock()
    81  	if len(globalLocalSetDrives) == 0 {
    82  		for _, drive := range globalLocalDrives {
    83  			if drive != nil && drive.Endpoint().Equal(endpoint) {
    84  				return drive
    85  			}
    86  		}
    87  	}
    88  	return globalLocalSetDrives[endpoint.PoolIdx][endpoint.SetIdx][endpoint.DiskIdx]
    89  }
    90  
    91  func (s *storageRESTServer) getStorage() StorageAPI {
    92  	return getStorageViaEndpoint(s.endpoint)
    93  }
    94  
    95  func (s *storageRESTServer) writeErrorResponse(w http.ResponseWriter, err error) {
    96  	err = unwrapAll(err)
    97  	switch err {
    98  	case errDiskStale:
    99  		w.WriteHeader(http.StatusPreconditionFailed)
   100  	case errFileNotFound, errFileVersionNotFound:
   101  		w.WriteHeader(http.StatusNotFound)
   102  	case errInvalidAccessKeyID, errAccessKeyDisabled, errNoAuthToken, errMalformedAuth, errAuthentication, errSkewedAuthTime:
   103  		w.WriteHeader(http.StatusUnauthorized)
   104  	case context.Canceled, context.DeadlineExceeded:
   105  		w.WriteHeader(499)
   106  	default:
   107  		w.WriteHeader(http.StatusForbidden)
   108  	}
   109  	w.Write([]byte(err.Error()))
   110  }
   111  
   112  // DefaultSkewTime - skew time is 15 minutes between minio peers.
   113  const DefaultSkewTime = 15 * time.Minute
   114  
   115  // Authenticates storage client's requests and validates for skewed time.
   116  func storageServerRequestValidate(r *http.Request) error {
   117  	token, err := jwtreq.AuthorizationHeaderExtractor.ExtractToken(r)
   118  	if err != nil {
   119  		if err == jwtreq.ErrNoTokenInRequest {
   120  			return errNoAuthToken
   121  		}
   122  		return errMalformedAuth
   123  	}
   124  
   125  	claims := xjwt.NewStandardClaims()
   126  	if err = xjwt.ParseWithStandardClaims(token, claims, []byte(globalActiveCred.SecretKey)); err != nil {
   127  		return errAuthentication
   128  	}
   129  
   130  	owner := claims.AccessKey == globalActiveCred.AccessKey || claims.Subject == globalActiveCred.AccessKey
   131  	if !owner {
   132  		return errAuthentication
   133  	}
   134  
   135  	if claims.Audience != r.URL.RawQuery {
   136  		return errAuthentication
   137  	}
   138  
   139  	requestTimeStr := r.Header.Get("X-Minio-Time")
   140  	requestTime, err := time.Parse(time.RFC3339, requestTimeStr)
   141  	if err != nil {
   142  		return errMalformedAuth
   143  	}
   144  	utcNow := UTCNow()
   145  	delta := requestTime.Sub(utcNow)
   146  	if delta < 0 {
   147  		delta *= -1
   148  	}
   149  	if delta > DefaultSkewTime {
   150  		return errSkewedAuthTime
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  // IsAuthValid - To authenticate and verify the time difference.
   157  func (s *storageRESTServer) IsAuthValid(w http.ResponseWriter, r *http.Request) bool {
   158  	if s.getStorage() == nil {
   159  		s.writeErrorResponse(w, errDiskNotFound)
   160  		return false
   161  	}
   162  
   163  	if err := storageServerRequestValidate(r); err != nil {
   164  		s.writeErrorResponse(w, err)
   165  		return false
   166  	}
   167  
   168  	return true
   169  }
   170  
   171  // IsValid - To authenticate and check if the disk-id in the request corresponds to the underlying disk.
   172  func (s *storageRESTServer) IsValid(w http.ResponseWriter, r *http.Request) bool {
   173  	if !s.IsAuthValid(w, r) {
   174  		return false
   175  	}
   176  
   177  	if err := r.ParseForm(); err != nil {
   178  		s.writeErrorResponse(w, err)
   179  		return false
   180  	}
   181  
   182  	diskID := r.Form.Get(storageRESTDiskID)
   183  	if diskID == "" {
   184  		// Request sent empty disk-id, we allow the request
   185  		// as the peer might be coming up and trying to read format.json
   186  		// or create format.json
   187  		return true
   188  	}
   189  
   190  	storedDiskID, err := s.getStorage().GetDiskID()
   191  	if err != nil {
   192  		s.writeErrorResponse(w, err)
   193  		return false
   194  	}
   195  
   196  	if diskID != storedDiskID {
   197  		s.writeErrorResponse(w, errDiskStale)
   198  		return false
   199  	}
   200  
   201  	// If format.json is available and request sent the right disk-id, we allow the request
   202  	return true
   203  }
   204  
   205  // checkID - check if the disk-id in the request corresponds to the underlying disk.
   206  func (s *storageRESTServer) checkID(wantID string) bool {
   207  	if s.getStorage() == nil {
   208  		return false
   209  	}
   210  	if wantID == "" {
   211  		// Request sent empty disk-id, we allow the request
   212  		// as the peer might be coming up and trying to read format.json
   213  		// or create format.json
   214  		return true
   215  	}
   216  
   217  	storedDiskID, err := s.getStorage().GetDiskID()
   218  	if err != nil {
   219  		return false
   220  	}
   221  
   222  	return wantID == storedDiskID
   223  }
   224  
   225  // HealthHandler handler checks if disk is stale
   226  func (s *storageRESTServer) HealthHandler(w http.ResponseWriter, r *http.Request) {
   227  	s.IsValid(w, r)
   228  }
   229  
   230  // DiskInfoHandler - returns disk info.
   231  func (s *storageRESTServer) DiskInfoHandler(opts *DiskInfoOptions) (*DiskInfo, *grid.RemoteErr) {
   232  	if !s.checkID(opts.DiskID) {
   233  		return nil, grid.NewRemoteErr(errDiskNotFound)
   234  	}
   235  	info, err := s.getStorage().DiskInfo(context.Background(), *opts)
   236  	if err != nil {
   237  		info.Error = err.Error()
   238  	}
   239  	return &info, nil
   240  }
   241  
   242  func (s *storageRESTServer) NSScannerHandler(ctx context.Context, params *nsScannerOptions, out chan<- *nsScannerResp) *grid.RemoteErr {
   243  	if !s.checkID(params.DiskID) {
   244  		return grid.NewRemoteErr(errDiskNotFound)
   245  	}
   246  	if params.Cache == nil {
   247  		return grid.NewRemoteErrString("NSScannerHandler: provided cache is nil")
   248  	}
   249  
   250  	// Collect updates, stream them before the full cache is sent.
   251  	updates := make(chan dataUsageEntry, 1)
   252  	var wg sync.WaitGroup
   253  	wg.Add(1)
   254  	go func() {
   255  		defer wg.Done()
   256  		for update := range updates {
   257  			resp := storageNSScannerRPC.NewResponse()
   258  			resp.Update = &update
   259  			out <- resp
   260  		}
   261  	}()
   262  	ui, err := s.getStorage().NSScanner(ctx, *params.Cache, updates, madmin.HealScanMode(params.ScanMode), nil)
   263  	wg.Wait()
   264  	if err != nil {
   265  		return grid.NewRemoteErr(err)
   266  	}
   267  	// Send final response.
   268  	resp := storageNSScannerRPC.NewResponse()
   269  	resp.Final = &ui
   270  	out <- resp
   271  	return nil
   272  }
   273  
   274  // MakeVolHandler - make a volume.
   275  func (s *storageRESTServer) MakeVolHandler(w http.ResponseWriter, r *http.Request) {
   276  	if !s.IsValid(w, r) {
   277  		return
   278  	}
   279  	volume := r.Form.Get(storageRESTVolume)
   280  	err := s.getStorage().MakeVol(r.Context(), volume)
   281  	if err != nil {
   282  		s.writeErrorResponse(w, err)
   283  	}
   284  }
   285  
   286  // MakeVolBulkHandler - create multiple volumes as a bulk operation.
   287  func (s *storageRESTServer) MakeVolBulkHandler(w http.ResponseWriter, r *http.Request) {
   288  	if !s.IsValid(w, r) {
   289  		return
   290  	}
   291  	volumes := strings.Split(r.Form.Get(storageRESTVolumes), ",")
   292  	err := s.getStorage().MakeVolBulk(r.Context(), volumes...)
   293  	if err != nil {
   294  		s.writeErrorResponse(w, err)
   295  	}
   296  }
   297  
   298  // StatVolHandler - stat a volume.
   299  func (s *storageRESTServer) StatVolHandler(params *grid.MSS) (*VolInfo, *grid.RemoteErr) {
   300  	if !s.checkID(params.Get(storageRESTDiskID)) {
   301  		return nil, grid.NewRemoteErr(errDiskNotFound)
   302  	}
   303  	info, err := s.getStorage().StatVol(context.Background(), params.Get(storageRESTVolume))
   304  	if err != nil {
   305  		return nil, grid.NewRemoteErr(err)
   306  	}
   307  	return &info, nil
   308  }
   309  
   310  // AppendFileHandler - append data from the request to the file specified.
   311  func (s *storageRESTServer) AppendFileHandler(w http.ResponseWriter, r *http.Request) {
   312  	if !s.IsValid(w, r) {
   313  		return
   314  	}
   315  	volume := r.Form.Get(storageRESTVolume)
   316  	filePath := r.Form.Get(storageRESTFilePath)
   317  
   318  	buf := make([]byte, r.ContentLength)
   319  	_, err := io.ReadFull(r.Body, buf)
   320  	if err != nil {
   321  		s.writeErrorResponse(w, err)
   322  		return
   323  	}
   324  	err = s.getStorage().AppendFile(r.Context(), volume, filePath, buf)
   325  	if err != nil {
   326  		s.writeErrorResponse(w, err)
   327  	}
   328  }
   329  
   330  // CreateFileHandler - copy the contents from the request.
   331  func (s *storageRESTServer) CreateFileHandler(w http.ResponseWriter, r *http.Request) {
   332  	if !s.IsValid(w, r) {
   333  		return
   334  	}
   335  
   336  	volume := r.Form.Get(storageRESTVolume)
   337  	filePath := r.Form.Get(storageRESTFilePath)
   338  	origvolume := r.Form.Get(storageRESTOrigVolume)
   339  
   340  	fileSizeStr := r.Form.Get(storageRESTLength)
   341  	fileSize, err := strconv.Atoi(fileSizeStr)
   342  	if err != nil {
   343  		s.writeErrorResponse(w, err)
   344  		return
   345  	}
   346  
   347  	done, body := keepHTTPReqResponseAlive(w, r)
   348  	done(s.getStorage().CreateFile(r.Context(), origvolume, volume, filePath, int64(fileSize), body))
   349  }
   350  
   351  // DeleteVersionHandler delete updated metadata.
   352  func (s *storageRESTServer) DeleteVersionHandler(p *DeleteVersionHandlerParams) (np grid.NoPayload, gerr *grid.RemoteErr) {
   353  	if !s.checkID(p.DiskID) {
   354  		return np, grid.NewRemoteErr(errDiskNotFound)
   355  	}
   356  	volume := p.Volume
   357  	filePath := p.FilePath
   358  	forceDelMarker := p.ForceDelMarker
   359  
   360  	opts := DeleteOptions{}
   361  	err := s.getStorage().DeleteVersion(context.Background(), volume, filePath, p.FI, forceDelMarker, opts)
   362  	return np, grid.NewRemoteErr(err)
   363  }
   364  
   365  // ReadVersionHandlerWS read metadata of versionID
   366  func (s *storageRESTServer) ReadVersionHandlerWS(params *grid.MSS) (*FileInfo, *grid.RemoteErr) {
   367  	if !s.checkID(params.Get(storageRESTDiskID)) {
   368  		return nil, grid.NewRemoteErr(errDiskNotFound)
   369  	}
   370  	origvolume := params.Get(storageRESTOrigVolume)
   371  	volume := params.Get(storageRESTVolume)
   372  	filePath := params.Get(storageRESTFilePath)
   373  	versionID := params.Get(storageRESTVersionID)
   374  	readData, err := strconv.ParseBool(params.Get(storageRESTReadData))
   375  	if err != nil {
   376  		return nil, grid.NewRemoteErr(err)
   377  	}
   378  
   379  	healing, err := strconv.ParseBool(params.Get(storageRESTHealing))
   380  	if err != nil {
   381  		return nil, grid.NewRemoteErr(err)
   382  	}
   383  
   384  	fi, err := s.getStorage().ReadVersion(context.Background(), origvolume, volume, filePath, versionID, ReadOptions{ReadData: readData, Healing: healing})
   385  	if err != nil {
   386  		return nil, grid.NewRemoteErr(err)
   387  	}
   388  	return &fi, nil
   389  }
   390  
   391  // ReadVersionHandler read metadata of versionID
   392  func (s *storageRESTServer) ReadVersionHandler(w http.ResponseWriter, r *http.Request) {
   393  	if !s.IsValid(w, r) {
   394  		return
   395  	}
   396  	origvolume := r.Form.Get(storageRESTOrigVolume)
   397  	volume := r.Form.Get(storageRESTVolume)
   398  	filePath := r.Form.Get(storageRESTFilePath)
   399  	versionID := r.Form.Get(storageRESTVersionID)
   400  	readData, err := strconv.ParseBool(r.Form.Get(storageRESTReadData))
   401  	if err != nil {
   402  		s.writeErrorResponse(w, err)
   403  		return
   404  	}
   405  	healing, err := strconv.ParseBool(r.Form.Get(storageRESTHealing))
   406  	if err != nil {
   407  		s.writeErrorResponse(w, err)
   408  		return
   409  	}
   410  	fi, err := s.getStorage().ReadVersion(r.Context(), origvolume, volume, filePath, versionID, ReadOptions{ReadData: readData, Healing: healing})
   411  	if err != nil {
   412  		s.writeErrorResponse(w, err)
   413  		return
   414  	}
   415  
   416  	logger.LogIf(r.Context(), msgp.Encode(w, &fi))
   417  }
   418  
   419  // WriteMetadataHandler rpc handler to write new updated metadata.
   420  func (s *storageRESTServer) WriteMetadataHandler(p *MetadataHandlerParams) (np grid.NoPayload, gerr *grid.RemoteErr) {
   421  	if !s.checkID(p.DiskID) {
   422  		return grid.NewNPErr(errDiskNotFound)
   423  	}
   424  
   425  	volume := p.Volume
   426  	filePath := p.FilePath
   427  	origvolume := p.OrigVolume
   428  
   429  	err := s.getStorage().WriteMetadata(context.Background(), origvolume, volume, filePath, p.FI)
   430  	return np, grid.NewRemoteErr(err)
   431  }
   432  
   433  // UpdateMetadataHandler update new updated metadata.
   434  func (s *storageRESTServer) UpdateMetadataHandler(p *MetadataHandlerParams) (grid.NoPayload, *grid.RemoteErr) {
   435  	if !s.checkID(p.DiskID) {
   436  		return grid.NewNPErr(errDiskNotFound)
   437  	}
   438  	volume := p.Volume
   439  	filePath := p.FilePath
   440  
   441  	return grid.NewNPErr(s.getStorage().UpdateMetadata(context.Background(), volume, filePath, p.FI, p.UpdateOpts))
   442  }
   443  
   444  // CheckPartsHandler - check if a file metadata exists.
   445  func (s *storageRESTServer) CheckPartsHandler(p *CheckPartsHandlerParams) (grid.NoPayload, *grid.RemoteErr) {
   446  	if !s.checkID(p.DiskID) {
   447  		return grid.NewNPErr(errDiskNotFound)
   448  	}
   449  	volume := p.Volume
   450  	filePath := p.FilePath
   451  	return grid.NewNPErr(s.getStorage().CheckParts(context.Background(), volume, filePath, p.FI))
   452  }
   453  
   454  func (s *storageRESTServer) WriteAllHandler(p *WriteAllHandlerParams) (grid.NoPayload, *grid.RemoteErr) {
   455  	if !s.checkID(p.DiskID) {
   456  		return grid.NewNPErr(errDiskNotFound)
   457  	}
   458  
   459  	volume := p.Volume
   460  	filePath := p.FilePath
   461  
   462  	return grid.NewNPErr(s.getStorage().WriteAll(context.Background(), volume, filePath, p.Buf))
   463  }
   464  
   465  // ReadAllHandler - read all the contents of a file.
   466  func (s *storageRESTServer) ReadAllHandler(p *ReadAllHandlerParams) (*grid.Bytes, *grid.RemoteErr) {
   467  	if !s.checkID(p.DiskID) {
   468  		return nil, grid.NewRemoteErr(errDiskNotFound)
   469  	}
   470  
   471  	volume := p.Volume
   472  	filePath := p.FilePath
   473  
   474  	buf, err := s.getStorage().ReadAll(context.Background(), volume, filePath)
   475  	return grid.NewBytesWith(buf), grid.NewRemoteErr(err)
   476  }
   477  
   478  // ReadXLHandler - read xl.meta for an object at path.
   479  func (s *storageRESTServer) ReadXLHandler(w http.ResponseWriter, r *http.Request) {
   480  	if !s.IsValid(w, r) {
   481  		return
   482  	}
   483  	volume := r.Form.Get(storageRESTVolume)
   484  	filePath := r.Form.Get(storageRESTFilePath)
   485  	readData, err := strconv.ParseBool(r.Form.Get(storageRESTReadData))
   486  	if err != nil {
   487  		s.writeErrorResponse(w, err)
   488  		return
   489  	}
   490  
   491  	rf, err := s.getStorage().ReadXL(r.Context(), volume, filePath, readData)
   492  	if err != nil {
   493  		s.writeErrorResponse(w, err)
   494  		return
   495  	}
   496  
   497  	logger.LogIf(r.Context(), msgp.Encode(w, &rf))
   498  }
   499  
   500  // ReadXLHandlerWS - read xl.meta for an object at path.
   501  func (s *storageRESTServer) ReadXLHandlerWS(params *grid.MSS) (*RawFileInfo, *grid.RemoteErr) {
   502  	if !s.checkID(params.Get(storageRESTDiskID)) {
   503  		return nil, grid.NewRemoteErr(errDiskNotFound)
   504  	}
   505  	volume := params.Get(storageRESTVolume)
   506  	filePath := params.Get(storageRESTFilePath)
   507  	readData, err := strconv.ParseBool(params.Get(storageRESTReadData))
   508  	if err != nil {
   509  		return nil, grid.NewRemoteErr(err)
   510  	}
   511  
   512  	rf, err := s.getStorage().ReadXL(context.Background(), volume, filePath, readData)
   513  	if err != nil {
   514  		return nil, grid.NewRemoteErr(err)
   515  	}
   516  
   517  	return &rf, nil
   518  }
   519  
   520  // ReadFileHandler - read section of a file.
   521  func (s *storageRESTServer) ReadFileHandler(w http.ResponseWriter, r *http.Request) {
   522  	if !s.IsValid(w, r) {
   523  		return
   524  	}
   525  	volume := r.Form.Get(storageRESTVolume)
   526  	filePath := r.Form.Get(storageRESTFilePath)
   527  	offset, err := strconv.Atoi(r.Form.Get(storageRESTOffset))
   528  	if err != nil {
   529  		s.writeErrorResponse(w, err)
   530  		return
   531  	}
   532  	length, err := strconv.Atoi(r.Form.Get(storageRESTLength))
   533  	if err != nil {
   534  		s.writeErrorResponse(w, err)
   535  		return
   536  	}
   537  	if offset < 0 || length < 0 {
   538  		s.writeErrorResponse(w, errInvalidArgument)
   539  		return
   540  	}
   541  	var verifier *BitrotVerifier
   542  	if r.Form.Get(storageRESTBitrotAlgo) != "" {
   543  		hashStr := r.Form.Get(storageRESTBitrotHash)
   544  		var hash []byte
   545  		hash, err = hex.DecodeString(hashStr)
   546  		if err != nil {
   547  			s.writeErrorResponse(w, err)
   548  			return
   549  		}
   550  		verifier = NewBitrotVerifier(BitrotAlgorithmFromString(r.Form.Get(storageRESTBitrotAlgo)), hash)
   551  	}
   552  	buf := make([]byte, length)
   553  	defer metaDataPoolPut(buf) // Reuse if we can.
   554  	_, err = s.getStorage().ReadFile(r.Context(), volume, filePath, int64(offset), buf, verifier)
   555  	if err != nil {
   556  		s.writeErrorResponse(w, err)
   557  		return
   558  	}
   559  	w.Header().Set(xhttp.ContentLength, strconv.Itoa(len(buf)))
   560  	w.Write(buf)
   561  }
   562  
   563  // ReadFileStreamHandler - read section of a file.
   564  func (s *storageRESTServer) ReadFileStreamHandler(w http.ResponseWriter, r *http.Request) {
   565  	if !s.IsValid(w, r) {
   566  		return
   567  	}
   568  	volume := r.Form.Get(storageRESTVolume)
   569  	filePath := r.Form.Get(storageRESTFilePath)
   570  	offset, err := strconv.Atoi(r.Form.Get(storageRESTOffset))
   571  	if err != nil {
   572  		s.writeErrorResponse(w, err)
   573  		return
   574  	}
   575  	length, err := strconv.Atoi(r.Form.Get(storageRESTLength))
   576  	if err != nil {
   577  		s.writeErrorResponse(w, err)
   578  		return
   579  	}
   580  
   581  	w.Header().Set(xhttp.ContentLength, strconv.Itoa(length))
   582  
   583  	rc, err := s.getStorage().ReadFileStream(r.Context(), volume, filePath, int64(offset), int64(length))
   584  	if err != nil {
   585  		s.writeErrorResponse(w, err)
   586  		return
   587  	}
   588  	defer rc.Close()
   589  
   590  	rf, ok := w.(io.ReaderFrom)
   591  	if ok && runtime.GOOS != "windows" {
   592  		// Attempt to use splice/sendfile() optimization, A very specific behavior mentioned below is necessary.
   593  		// See https://github.com/golang/go/blob/f7c5cbb82087c55aa82081e931e0142783700ce8/src/net/sendfile_linux.go#L20
   594  		// Windows can lock up with this optimization, so we fall back to regular copy.
   595  		sr, ok := rc.(*sendFileReader)
   596  		if ok {
   597  			_, err = rf.ReadFrom(sr.Reader)
   598  			if !xnet.IsNetworkOrHostDown(err, true) { // do not need to log disconnected clients
   599  				logger.LogIf(r.Context(), err)
   600  			}
   601  			if err == nil || !errors.Is(err, xhttp.ErrNotImplemented) {
   602  				return
   603  			}
   604  		}
   605  	} // Fallback to regular copy
   606  
   607  	_, err = xioutil.Copy(w, rc)
   608  	if !xnet.IsNetworkOrHostDown(err, true) { // do not need to log disconnected clients
   609  		logger.LogIf(r.Context(), err)
   610  	}
   611  }
   612  
   613  // ListDirHandler - list a directory.
   614  func (s *storageRESTServer) ListDirHandler(ctx context.Context, params *grid.MSS, out chan<- *ListDirResult) *grid.RemoteErr {
   615  	if !s.checkID(params.Get(storageRESTDiskID)) {
   616  		return grid.NewRemoteErr(errDiskNotFound)
   617  	}
   618  	volume := params.Get(storageRESTVolume)
   619  	dirPath := params.Get(storageRESTDirPath)
   620  	origvolume := params.Get(storageRESTOrigVolume)
   621  	count, err := strconv.Atoi(params.Get(storageRESTCount))
   622  	if err != nil {
   623  		return grid.NewRemoteErr(err)
   624  	}
   625  
   626  	entries, err := s.getStorage().ListDir(ctx, origvolume, volume, dirPath, count)
   627  	if err != nil {
   628  		return grid.NewRemoteErr(err)
   629  	}
   630  	out <- &ListDirResult{Entries: entries}
   631  	return nil
   632  }
   633  
   634  // DeleteFileHandler - delete a file.
   635  func (s *storageRESTServer) DeleteFileHandler(p *DeleteFileHandlerParams) (grid.NoPayload, *grid.RemoteErr) {
   636  	if !s.checkID(p.DiskID) {
   637  		return grid.NewNPErr(errDiskNotFound)
   638  	}
   639  	return grid.NewNPErr(s.getStorage().Delete(context.Background(), p.Volume, p.FilePath, p.Opts))
   640  }
   641  
   642  // DeleteVersionsErrsResp - collection of delete errors
   643  // for bulk version deletes
   644  type DeleteVersionsErrsResp struct {
   645  	Errs []error
   646  }
   647  
   648  // DeleteVersionsHandler - delete a set of a versions.
   649  func (s *storageRESTServer) DeleteVersionsHandler(w http.ResponseWriter, r *http.Request) {
   650  	if !s.IsValid(w, r) {
   651  		return
   652  	}
   653  
   654  	volume := r.Form.Get(storageRESTVolume)
   655  	totalVersions, err := strconv.Atoi(r.Form.Get(storageRESTTotalVersions))
   656  	if err != nil {
   657  		s.writeErrorResponse(w, err)
   658  		return
   659  	}
   660  
   661  	versions := make([]FileInfoVersions, totalVersions)
   662  	decoder := msgpNewReader(r.Body)
   663  	defer readMsgpReaderPoolPut(decoder)
   664  	for i := 0; i < totalVersions; i++ {
   665  		dst := &versions[i]
   666  		if err := dst.DecodeMsg(decoder); err != nil {
   667  			s.writeErrorResponse(w, err)
   668  			return
   669  		}
   670  	}
   671  
   672  	dErrsResp := &DeleteVersionsErrsResp{Errs: make([]error, totalVersions)}
   673  
   674  	setEventStreamHeaders(w)
   675  	encoder := gob.NewEncoder(w)
   676  	done := keepHTTPResponseAlive(w)
   677  
   678  	opts := DeleteOptions{}
   679  	errs := s.getStorage().DeleteVersions(r.Context(), volume, versions, opts)
   680  	done(nil)
   681  	for idx := range versions {
   682  		if errs[idx] != nil {
   683  			dErrsResp.Errs[idx] = StorageErr(errs[idx].Error())
   684  		}
   685  	}
   686  	encoder.Encode(dErrsResp)
   687  }
   688  
   689  // RenameDataHandler - renames a meta object and data dir to destination.
   690  func (s *storageRESTServer) RenameDataHandler(p *RenameDataHandlerParams) (*RenameDataResp, *grid.RemoteErr) {
   691  	if !s.checkID(p.DiskID) {
   692  		return nil, grid.NewRemoteErr(errDiskNotFound)
   693  	}
   694  
   695  	sign, err := s.getStorage().RenameData(context.Background(), p.SrcVolume, p.SrcPath, p.FI, p.DstVolume, p.DstPath, p.Opts)
   696  	resp := &RenameDataResp{
   697  		Signature: sign,
   698  	}
   699  	return resp, grid.NewRemoteErr(err)
   700  }
   701  
   702  // RenameFileHandler - rename a file from source to destination
   703  func (s *storageRESTServer) RenameFileHandler(p *RenameFileHandlerParams) (grid.NoPayload, *grid.RemoteErr) {
   704  	if !s.checkID(p.DiskID) {
   705  		return grid.NewNPErr(errDiskNotFound)
   706  	}
   707  	return grid.NewNPErr(s.getStorage().RenameFile(context.Background(), p.SrcVolume, p.SrcFilePath, p.DstVolume, p.DstFilePath))
   708  }
   709  
   710  // CleanAbandonedDataHandler - Clean unused data directories.
   711  func (s *storageRESTServer) CleanAbandonedDataHandler(w http.ResponseWriter, r *http.Request) {
   712  	if !s.IsValid(w, r) {
   713  		return
   714  	}
   715  	volume := r.Form.Get(storageRESTVolume)
   716  	filePath := r.Form.Get(storageRESTFilePath)
   717  	if volume == "" || filePath == "" {
   718  		return // Ignore
   719  	}
   720  	keepHTTPResponseAlive(w)(s.getStorage().CleanAbandonedData(r.Context(), volume, filePath))
   721  }
   722  
   723  // closeNotifier is itself a ReadCloser that will notify when either an error occurs or
   724  // the Close() function is called.
   725  type closeNotifier struct {
   726  	rc   io.ReadCloser
   727  	done chan struct{}
   728  }
   729  
   730  func (c *closeNotifier) Read(p []byte) (n int, err error) {
   731  	n, err = c.rc.Read(p)
   732  	if err != nil {
   733  		if c.done != nil {
   734  			xioutil.SafeClose(c.done)
   735  			c.done = nil
   736  		}
   737  	}
   738  	return n, err
   739  }
   740  
   741  func (c *closeNotifier) Close() error {
   742  	if c.done != nil {
   743  		xioutil.SafeClose(c.done)
   744  		c.done = nil
   745  	}
   746  	return c.rc.Close()
   747  }
   748  
   749  // keepHTTPReqResponseAlive can be used to avoid timeouts with long storage
   750  // operations, such as bitrot verification or data usage scanning.
   751  // Every 10 seconds a space character is sent.
   752  // keepHTTPReqResponseAlive will wait for the returned body to be read before starting the ticker.
   753  // The returned function should always be called to release resources.
   754  // An optional error can be sent which will be picked as text only error,
   755  // without its original type by the receiver.
   756  // waitForHTTPResponse should be used to the receiving side.
   757  func keepHTTPReqResponseAlive(w http.ResponseWriter, r *http.Request) (resp func(error), body io.ReadCloser) {
   758  	bodyDoneCh := make(chan struct{})
   759  	doneCh := make(chan error)
   760  	ctx := r.Context()
   761  	go func() {
   762  		canWrite := true
   763  		write := func(b []byte) {
   764  			if canWrite {
   765  				n, err := w.Write(b)
   766  				if err != nil || n != len(b) {
   767  					canWrite = false
   768  				}
   769  			}
   770  		}
   771  		// Wait for body to be read.
   772  		select {
   773  		case <-ctx.Done():
   774  		case <-bodyDoneCh:
   775  		case err := <-doneCh:
   776  			if err != nil {
   777  				write([]byte{1})
   778  				write([]byte(err.Error()))
   779  			} else {
   780  				write([]byte{0})
   781  			}
   782  			xioutil.SafeClose(doneCh)
   783  			return
   784  		}
   785  		defer xioutil.SafeClose(doneCh)
   786  		// Initiate ticker after body has been read.
   787  		ticker := time.NewTicker(time.Second * 10)
   788  		for {
   789  			select {
   790  			case <-ticker.C:
   791  				// Response not ready, write a filler byte.
   792  				write([]byte{32})
   793  				if canWrite {
   794  					w.(http.Flusher).Flush()
   795  				}
   796  			case err := <-doneCh:
   797  				if err != nil {
   798  					write([]byte{1})
   799  					write([]byte(err.Error()))
   800  				} else {
   801  					write([]byte{0})
   802  				}
   803  				ticker.Stop()
   804  				return
   805  			}
   806  		}
   807  	}()
   808  	return func(err error) {
   809  		if doneCh == nil {
   810  			return
   811  		}
   812  
   813  		// Indicate we are ready to write.
   814  		doneCh <- err
   815  
   816  		// Wait for channel to be closed so we don't race on writes.
   817  		<-doneCh
   818  
   819  		// Clear so we can be called multiple times without crashing.
   820  		doneCh = nil
   821  	}, &closeNotifier{rc: r.Body, done: bodyDoneCh}
   822  }
   823  
   824  // keepHTTPResponseAlive can be used to avoid timeouts with long storage
   825  // operations, such as bitrot verification or data usage scanning.
   826  // keepHTTPResponseAlive may NOT be used until the request body has been read,
   827  // use keepHTTPReqResponseAlive instead.
   828  // Every 10 seconds a space character is sent.
   829  // The returned function should always be called to release resources.
   830  // An optional error can be sent which will be picked as text only error,
   831  // without its original type by the receiver.
   832  // waitForHTTPResponse should be used to the receiving side.
   833  func keepHTTPResponseAlive(w http.ResponseWriter) func(error) {
   834  	doneCh := make(chan error)
   835  	go func() {
   836  		canWrite := true
   837  		write := func(b []byte) {
   838  			if canWrite {
   839  				n, err := w.Write(b)
   840  				if err != nil || n != len(b) {
   841  					canWrite = false
   842  				}
   843  			}
   844  		}
   845  		defer xioutil.SafeClose(doneCh)
   846  		ticker := time.NewTicker(time.Second * 10)
   847  		defer ticker.Stop()
   848  		for {
   849  			select {
   850  			case <-ticker.C:
   851  				// Response not ready, write a filler byte.
   852  				write([]byte{32})
   853  				if canWrite {
   854  					w.(http.Flusher).Flush()
   855  				}
   856  			case err := <-doneCh:
   857  				if err != nil {
   858  					write([]byte{1})
   859  					write([]byte(err.Error()))
   860  				} else {
   861  					write([]byte{0})
   862  				}
   863  				return
   864  			}
   865  		}
   866  	}()
   867  	return func(err error) {
   868  		if doneCh == nil {
   869  			return
   870  		}
   871  		// Indicate we are ready to write.
   872  		doneCh <- err
   873  
   874  		// Wait for channel to be closed so we don't race on writes.
   875  		<-doneCh
   876  
   877  		// Clear so we can be called multiple times without crashing.
   878  		doneCh = nil
   879  	}
   880  }
   881  
   882  // waitForHTTPResponse will wait for responses where keepHTTPResponseAlive
   883  // has been used.
   884  // The returned reader contains the payload.
   885  func waitForHTTPResponse(respBody io.Reader) (io.Reader, error) {
   886  	reader := bufio.NewReader(respBody)
   887  	for {
   888  		b, err := reader.ReadByte()
   889  		if err != nil {
   890  			return nil, err
   891  		}
   892  		// Check if we have a response ready or a filler byte.
   893  		switch b {
   894  		case 0:
   895  			return reader, nil
   896  		case 1:
   897  			errorText, err := io.ReadAll(reader)
   898  			if err != nil {
   899  				return nil, err
   900  			}
   901  			return nil, errors.New(string(errorText))
   902  		case 32:
   903  			continue
   904  		default:
   905  			return nil, fmt.Errorf("unexpected filler byte: %d", b)
   906  		}
   907  	}
   908  }
   909  
   910  // httpStreamResponse allows streaming a response, but still send an error.
   911  type httpStreamResponse struct {
   912  	done  chan error
   913  	block chan []byte
   914  	err   error
   915  }
   916  
   917  // Write part of the streaming response.
   918  // Note that upstream errors are currently not forwarded, but may be in the future.
   919  func (h *httpStreamResponse) Write(b []byte) (int, error) {
   920  	if len(b) == 0 || h.err != nil {
   921  		// Ignore 0 length blocks
   922  		return 0, h.err
   923  	}
   924  	tmp := make([]byte, len(b))
   925  	copy(tmp, b)
   926  	h.block <- tmp
   927  	return len(b), h.err
   928  }
   929  
   930  // CloseWithError will close the stream and return the specified error.
   931  // This can be done several times, but only the first error will be sent.
   932  // After calling this the stream should not be written to.
   933  func (h *httpStreamResponse) CloseWithError(err error) {
   934  	if h.done == nil {
   935  		return
   936  	}
   937  	h.done <- err
   938  	h.err = err
   939  	// Indicates that the response is done.
   940  	<-h.done
   941  	h.done = nil
   942  }
   943  
   944  // streamHTTPResponse can be used to avoid timeouts with long storage
   945  // operations, such as bitrot verification or data usage scanning.
   946  // Every 10 seconds a space character is sent.
   947  // The returned function should always be called to release resources.
   948  // An optional error can be sent which will be picked as text only error,
   949  // without its original type by the receiver.
   950  // waitForHTTPStream should be used to the receiving side.
   951  func streamHTTPResponse(w http.ResponseWriter) *httpStreamResponse {
   952  	doneCh := make(chan error)
   953  	blockCh := make(chan []byte)
   954  	h := httpStreamResponse{done: doneCh, block: blockCh}
   955  	go func() {
   956  		canWrite := true
   957  		write := func(b []byte) {
   958  			if canWrite {
   959  				n, err := w.Write(b)
   960  				if err != nil || n != len(b) {
   961  					canWrite = false
   962  				}
   963  			}
   964  		}
   965  
   966  		ticker := time.NewTicker(time.Second * 10)
   967  		defer ticker.Stop()
   968  		for {
   969  			select {
   970  			case <-ticker.C:
   971  				// Response not ready, write a filler byte.
   972  				write([]byte{32})
   973  				if canWrite {
   974  					w.(http.Flusher).Flush()
   975  				}
   976  			case err := <-doneCh:
   977  				if err != nil {
   978  					write([]byte{1})
   979  					write([]byte(err.Error()))
   980  				} else {
   981  					write([]byte{0})
   982  				}
   983  				xioutil.SafeClose(doneCh)
   984  				return
   985  			case block := <-blockCh:
   986  				var tmp [5]byte
   987  				tmp[0] = 2
   988  				binary.LittleEndian.PutUint32(tmp[1:], uint32(len(block)))
   989  				write(tmp[:])
   990  				write(block)
   991  				if canWrite {
   992  					w.(http.Flusher).Flush()
   993  				}
   994  			}
   995  		}
   996  	}()
   997  	return &h
   998  }
   999  
  1000  var poolBuf8k = sync.Pool{
  1001  	New: func() interface{} {
  1002  		b := make([]byte, 8192)
  1003  		return &b
  1004  	},
  1005  }
  1006  
  1007  var poolBuf128k = sync.Pool{
  1008  	New: func() interface{} {
  1009  		b := make([]byte, 128<<10)
  1010  		return b
  1011  	},
  1012  }
  1013  
  1014  // waitForHTTPStream will wait for responses where
  1015  // streamHTTPResponse has been used.
  1016  // The returned reader contains the payload and must be closed if no error is returned.
  1017  func waitForHTTPStream(respBody io.ReadCloser, w io.Writer) error {
  1018  	var tmp [1]byte
  1019  	// 8K copy buffer, reused for less allocs...
  1020  	bufp := poolBuf8k.Get().(*[]byte)
  1021  	buf := *bufp
  1022  	defer poolBuf8k.Put(bufp)
  1023  	for {
  1024  		_, err := io.ReadFull(respBody, tmp[:])
  1025  		if err != nil {
  1026  			return err
  1027  		}
  1028  		// Check if we have a response ready or a filler byte.
  1029  		switch tmp[0] {
  1030  		case 0:
  1031  			// 0 is unbuffered, copy the rest.
  1032  			_, err := io.CopyBuffer(w, respBody, buf)
  1033  			if err == io.EOF {
  1034  				return nil
  1035  			}
  1036  			return err
  1037  		case 1:
  1038  			errorText, err := io.ReadAll(respBody)
  1039  			if err != nil {
  1040  				return err
  1041  			}
  1042  			return errors.New(string(errorText))
  1043  		case 2:
  1044  			// Block of data
  1045  			var tmp [4]byte
  1046  			_, err := io.ReadFull(respBody, tmp[:])
  1047  			if err != nil {
  1048  				return err
  1049  			}
  1050  			length := binary.LittleEndian.Uint32(tmp[:])
  1051  			n, err := io.CopyBuffer(w, io.LimitReader(respBody, int64(length)), buf)
  1052  			if err != nil {
  1053  				return err
  1054  			}
  1055  			if n != int64(length) {
  1056  				return io.ErrUnexpectedEOF
  1057  			}
  1058  			continue
  1059  		case 32:
  1060  			continue
  1061  		default:
  1062  			return fmt.Errorf("unexpected filler byte: %d", tmp[0])
  1063  		}
  1064  	}
  1065  }
  1066  
  1067  // VerifyFileResp - VerifyFile()'s response.
  1068  type VerifyFileResp struct {
  1069  	Err error
  1070  }
  1071  
  1072  // VerifyFileHandler - Verify all part of file for bitrot errors.
  1073  func (s *storageRESTServer) VerifyFileHandler(w http.ResponseWriter, r *http.Request) {
  1074  	if !s.IsValid(w, r) {
  1075  		return
  1076  	}
  1077  	volume := r.Form.Get(storageRESTVolume)
  1078  	filePath := r.Form.Get(storageRESTFilePath)
  1079  
  1080  	if r.ContentLength < 0 {
  1081  		s.writeErrorResponse(w, errInvalidArgument)
  1082  		return
  1083  	}
  1084  
  1085  	var fi FileInfo
  1086  	if err := msgp.Decode(r.Body, &fi); err != nil {
  1087  		s.writeErrorResponse(w, err)
  1088  		return
  1089  	}
  1090  
  1091  	setEventStreamHeaders(w)
  1092  	encoder := gob.NewEncoder(w)
  1093  	done := keepHTTPResponseAlive(w)
  1094  	err := s.getStorage().VerifyFile(r.Context(), volume, filePath, fi)
  1095  	done(nil)
  1096  	vresp := &VerifyFileResp{}
  1097  	if err != nil {
  1098  		vresp.Err = StorageErr(err.Error())
  1099  	}
  1100  	encoder.Encode(vresp)
  1101  }
  1102  
  1103  func checkDiskFatalErrs(errs []error) error {
  1104  	// This returns a common error if all errors are
  1105  	// same errors, then there is no point starting
  1106  	// the server.
  1107  	if countErrs(errs, errUnsupportedDisk) == len(errs) {
  1108  		return errUnsupportedDisk
  1109  	}
  1110  
  1111  	if countErrs(errs, errDiskAccessDenied) == len(errs) {
  1112  		return errDiskAccessDenied
  1113  	}
  1114  
  1115  	if countErrs(errs, errFileAccessDenied) == len(errs) {
  1116  		return errDiskAccessDenied
  1117  	}
  1118  
  1119  	if countErrs(errs, errDiskNotDir) == len(errs) {
  1120  		return errDiskNotDir
  1121  	}
  1122  
  1123  	if countErrs(errs, errFaultyDisk) == len(errs) {
  1124  		return errFaultyDisk
  1125  	}
  1126  
  1127  	if countErrs(errs, errXLBackend) == len(errs) {
  1128  		return errXLBackend
  1129  	}
  1130  
  1131  	return nil
  1132  }
  1133  
  1134  // A single function to write certain errors to be fatal
  1135  // or informative based on the `exit` flag, please look
  1136  // at each implementation of error for added hints.
  1137  //
  1138  // FIXME: This is an unusual function but serves its purpose for
  1139  // now, need to revisit the overall erroring structure here.
  1140  // Do not like it :-(
  1141  func logFatalErrs(err error, endpoint Endpoint, exit bool) {
  1142  	switch {
  1143  	case errors.Is(err, errXLBackend):
  1144  		logger.Fatal(config.ErrInvalidXLValue(err), "Unable to initialize backend")
  1145  	case errors.Is(err, errUnsupportedDisk):
  1146  		var hint string
  1147  		if endpoint.URL != nil {
  1148  			hint = fmt.Sprintf("Drive '%s' does not support O_DIRECT flags, MinIO erasure coding requires filesystems with O_DIRECT support", endpoint.Path)
  1149  		} else {
  1150  			hint = "Drives do not support O_DIRECT flags, MinIO erasure coding requires filesystems with O_DIRECT support"
  1151  		}
  1152  		logger.Fatal(config.ErrUnsupportedBackend(err).Hint(hint), "Unable to initialize backend")
  1153  	case errors.Is(err, errDiskNotDir):
  1154  		var hint string
  1155  		if endpoint.URL != nil {
  1156  			hint = fmt.Sprintf("Drive '%s' is not a directory, MinIO erasure coding needs a directory", endpoint.Path)
  1157  		} else {
  1158  			hint = "Drives are not directories, MinIO erasure coding needs directories"
  1159  		}
  1160  		logger.Fatal(config.ErrUnableToWriteInBackend(err).Hint(hint), "Unable to initialize backend")
  1161  	case errors.Is(err, errDiskAccessDenied):
  1162  		// Show a descriptive error with a hint about how to fix it.
  1163  		var username string
  1164  		if u, err := user.Current(); err == nil {
  1165  			username = u.Username
  1166  		} else {
  1167  			username = "<your-username>"
  1168  		}
  1169  		var hint string
  1170  		if endpoint.URL != nil {
  1171  			hint = fmt.Sprintf("Run the following command to add write permissions: `sudo chown -R %s %s && sudo chmod u+rxw %s`",
  1172  				username, endpoint.Path, endpoint.Path)
  1173  		} else {
  1174  			hint = fmt.Sprintf("Run the following command to add write permissions: `sudo chown -R %s. <path> && sudo chmod u+rxw <path>`", username)
  1175  		}
  1176  		if !exit {
  1177  			logger.LogOnceIf(GlobalContext, fmt.Errorf("Drive is not writable %s, %s", endpoint, hint), "log-fatal-errs")
  1178  		} else {
  1179  			logger.Fatal(config.ErrUnableToWriteInBackend(err).Hint(hint), "Unable to initialize backend")
  1180  		}
  1181  	case errors.Is(err, errFaultyDisk):
  1182  		if !exit {
  1183  			logger.LogOnceIf(GlobalContext, fmt.Errorf("Drive is faulty at %s, please replace the drive - drive will be offline", endpoint), "log-fatal-errs")
  1184  		} else {
  1185  			logger.Fatal(err, "Unable to initialize backend")
  1186  		}
  1187  	case errors.Is(err, errDiskFull):
  1188  		if !exit {
  1189  			logger.LogOnceIf(GlobalContext, fmt.Errorf("Drive is already full at %s, incoming I/O will fail - drive will be offline", endpoint), "log-fatal-errs")
  1190  		} else {
  1191  			logger.Fatal(err, "Unable to initialize backend")
  1192  		}
  1193  	default:
  1194  		if !exit {
  1195  			logger.LogOnceIf(GlobalContext, fmt.Errorf("Drive %s returned an unexpected error: %w, please investigate - drive will be offline", endpoint, err), "log-fatal-errs")
  1196  		} else {
  1197  			logger.Fatal(err, "Unable to initialize backend")
  1198  		}
  1199  	}
  1200  }
  1201  
  1202  // StatInfoFile returns file stat info.
  1203  func (s *storageRESTServer) StatInfoFile(w http.ResponseWriter, r *http.Request) {
  1204  	if !s.IsValid(w, r) {
  1205  		return
  1206  	}
  1207  	volume := r.Form.Get(storageRESTVolume)
  1208  	filePath := r.Form.Get(storageRESTFilePath)
  1209  	glob := r.Form.Get(storageRESTGlob)
  1210  	done := keepHTTPResponseAlive(w)
  1211  	stats, err := s.getStorage().StatInfoFile(r.Context(), volume, filePath, glob == "true")
  1212  	done(err)
  1213  	if err != nil {
  1214  		return
  1215  	}
  1216  	for _, si := range stats {
  1217  		msgp.Encode(w, &si)
  1218  	}
  1219  }
  1220  
  1221  // ReadMultiple returns multiple files
  1222  func (s *storageRESTServer) ReadMultiple(w http.ResponseWriter, r *http.Request) {
  1223  	if !s.IsValid(w, r) {
  1224  		return
  1225  	}
  1226  	rw := streamHTTPResponse(w)
  1227  	defer func() {
  1228  		if r := recover(); r != nil {
  1229  			debug.PrintStack()
  1230  			rw.CloseWithError(fmt.Errorf("panic: %v", r))
  1231  		}
  1232  	}()
  1233  
  1234  	var req ReadMultipleReq
  1235  	mr := msgpNewReader(r.Body)
  1236  	defer readMsgpReaderPoolPut(mr)
  1237  	err := req.DecodeMsg(mr)
  1238  	if err != nil {
  1239  		rw.CloseWithError(err)
  1240  		return
  1241  	}
  1242  
  1243  	mw := msgp.NewWriter(rw)
  1244  	responses := make(chan ReadMultipleResp, len(req.Files))
  1245  	var wg sync.WaitGroup
  1246  	wg.Add(1)
  1247  	go func() {
  1248  		defer wg.Done()
  1249  		for resp := range responses {
  1250  			err := resp.EncodeMsg(mw)
  1251  			if err != nil {
  1252  				rw.CloseWithError(err)
  1253  				return
  1254  			}
  1255  			mw.Flush()
  1256  		}
  1257  	}()
  1258  	err = s.getStorage().ReadMultiple(r.Context(), req, responses)
  1259  	wg.Wait()
  1260  	rw.CloseWithError(err)
  1261  }
  1262  
  1263  // globalLocalSetDrives is used for local drive as well as remote REST
  1264  // API caller for other nodes to talk to this node.
  1265  //
  1266  // Any updates to this must be serialized via globalLocalDrivesMu (locker)
  1267  var globalLocalSetDrives [][][]StorageAPI
  1268  
  1269  // registerStorageRESTHandlers - register storage rpc router.
  1270  func registerStorageRESTHandlers(router *mux.Router, endpointServerPools EndpointServerPools, gm *grid.Manager) {
  1271  	h := func(f http.HandlerFunc) http.HandlerFunc {
  1272  		return collectInternodeStats(httpTraceHdrs(f))
  1273  	}
  1274  
  1275  	globalLocalSetDrives = make([][][]StorageAPI, len(endpointServerPools))
  1276  	for pool := range globalLocalSetDrives {
  1277  		globalLocalSetDrives[pool] = make([][]StorageAPI, endpointServerPools[pool].SetCount)
  1278  		for set := range globalLocalSetDrives[pool] {
  1279  			globalLocalSetDrives[pool][set] = make([]StorageAPI, endpointServerPools[pool].DrivesPerSet)
  1280  		}
  1281  	}
  1282  	for _, serverPool := range endpointServerPools {
  1283  		for _, endpoint := range serverPool.Endpoints {
  1284  			if !endpoint.IsLocal {
  1285  				continue
  1286  			}
  1287  
  1288  			server := &storageRESTServer{
  1289  				endpoint: endpoint,
  1290  			}
  1291  
  1292  			subrouter := router.PathPrefix(path.Join(storageRESTPrefix, endpoint.Path)).Subrouter()
  1293  
  1294  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodHealth).HandlerFunc(h(server.HealthHandler))
  1295  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodAppendFile).HandlerFunc(h(server.AppendFileHandler))
  1296  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadVersion).HandlerFunc(h(server.ReadVersionHandler))
  1297  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadXL).HandlerFunc(h(server.ReadXLHandler))
  1298  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodCreateFile).HandlerFunc(h(server.CreateFileHandler))
  1299  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadFile).HandlerFunc(h(server.ReadFileHandler))
  1300  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadFileStream).HandlerFunc(h(server.ReadFileStreamHandler))
  1301  
  1302  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDeleteVersions).HandlerFunc(h(server.DeleteVersionsHandler))
  1303  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodVerifyFile).HandlerFunc(h(server.VerifyFileHandler))
  1304  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodStatInfoFile).HandlerFunc(h(server.StatInfoFile))
  1305  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadMultiple).HandlerFunc(h(server.ReadMultiple))
  1306  			subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodCleanAbandoned).HandlerFunc(h(server.CleanAbandonedDataHandler))
  1307  			logger.FatalIf(storageListDirRPC.RegisterNoInput(gm, server.ListDirHandler, endpoint.Path), "unable to register handler")
  1308  			logger.FatalIf(storageReadAllRPC.Register(gm, server.ReadAllHandler, endpoint.Path), "unable to register handler")
  1309  			logger.FatalIf(storageWriteAllRPC.Register(gm, server.WriteAllHandler, endpoint.Path), "unable to register handler")
  1310  			logger.FatalIf(storageRenameFileRPC.Register(gm, server.RenameFileHandler, endpoint.Path), "unable to register handler")
  1311  			logger.FatalIf(storageRenameDataRPC.Register(gm, server.RenameDataHandler, endpoint.Path), "unable to register handler")
  1312  			logger.FatalIf(storageDeleteFileRPC.Register(gm, server.DeleteFileHandler, endpoint.Path), "unable to register handler")
  1313  			logger.FatalIf(storageCheckPartsRPC.Register(gm, server.CheckPartsHandler, endpoint.Path), "unable to register handler")
  1314  			logger.FatalIf(storageReadVersionRPC.Register(gm, server.ReadVersionHandlerWS, endpoint.Path), "unable to register handler")
  1315  			logger.FatalIf(storageWriteMetadataRPC.Register(gm, server.WriteMetadataHandler, endpoint.Path), "unable to register handler")
  1316  			logger.FatalIf(storageUpdateMetadataRPC.Register(gm, server.UpdateMetadataHandler, endpoint.Path), "unable to register handler")
  1317  			logger.FatalIf(storageDeleteVersionRPC.Register(gm, server.DeleteVersionHandler, endpoint.Path), "unable to register handler")
  1318  			logger.FatalIf(storageReadXLRPC.Register(gm, server.ReadXLHandlerWS, endpoint.Path), "unable to register handler")
  1319  			logger.FatalIf(storageNSScannerRPC.RegisterNoInput(gm, server.NSScannerHandler, endpoint.Path), "unable to register handler")
  1320  			logger.FatalIf(storageDiskInfoRPC.Register(gm, server.DiskInfoHandler, endpoint.Path), "unable to register handler")
  1321  			logger.FatalIf(storageStatVolRPC.Register(gm, server.StatVolHandler, endpoint.Path), "unable to register handler")
  1322  			logger.FatalIf(gm.RegisterStreamingHandler(grid.HandlerWalkDir, grid.StreamHandler{
  1323  				Subroute:    endpoint.Path,
  1324  				Handle:      server.WalkDirHandler,
  1325  				OutCapacity: 1,
  1326  			}), "unable to register handler")
  1327  
  1328  			createStorage := func(server *storageRESTServer) bool {
  1329  				xl, err := newXLStorage(endpoint, false)
  1330  				if err != nil {
  1331  					// if supported errors don't fail, we proceed to
  1332  					// printing message and moving forward.
  1333  					if errors.Is(err, errDriveIsRoot) {
  1334  						err = fmt.Errorf("major: %v: minor: %v: %w", xl.major, xl.minor, err)
  1335  					}
  1336  					logFatalErrs(err, endpoint, false)
  1337  					return false
  1338  				}
  1339  				storage := newXLStorageDiskIDCheck(xl, true)
  1340  				storage.SetDiskID(xl.diskID)
  1341  				// We do not have to do SetFormatData() since 'xl'
  1342  				// already captures formatData cached.
  1343  
  1344  				globalLocalDrivesMu.Lock()
  1345  				defer globalLocalDrivesMu.Unlock()
  1346  
  1347  				globalLocalDrives = append(globalLocalDrives, storage)
  1348  				globalLocalSetDrives[endpoint.PoolIdx][endpoint.SetIdx][endpoint.DiskIdx] = storage
  1349  				return true
  1350  			}
  1351  
  1352  			if createStorage(server) {
  1353  				continue
  1354  			}
  1355  
  1356  			// Start async goroutine to create storage.
  1357  			go func(server *storageRESTServer) {
  1358  				for {
  1359  					time.Sleep(3 * time.Second)
  1360  					if createStorage(server) {
  1361  						return
  1362  					}
  1363  				}
  1364  			}(server)
  1365  
  1366  		}
  1367  	}
  1368  }