github.com/cs3org/reva/v2@v2.27.7/pkg/storage/utils/localfs/localfs_unix.go (about)

     1  // Copyright 2018-2021 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  //go:build !windows
    20  // +build !windows
    21  
    22  package localfs
    23  
    24  import (
    25  	"context"
    26  	"crypto/md5"
    27  	"encoding/binary"
    28  	"fmt"
    29  	"os"
    30  	"strings"
    31  	"syscall"
    32  
    33  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    34  	"github.com/cs3org/reva/v2/pkg/appctx"
    35  )
    36  
    37  // calcEtag will create an etag based on the md5 of
    38  // - mtime,
    39  // - inode (if available),
    40  // - device (if available) and
    41  // - size.
    42  // errors are logged, but an etag will still be returned
    43  func calcEtag(ctx context.Context, fi os.FileInfo) string {
    44  	log := appctx.GetLogger(ctx)
    45  	h := md5.New()
    46  	err := binary.Write(h, binary.BigEndian, fi.ModTime().UnixNano())
    47  	if err != nil {
    48  		log.Error().Err(err).Msg("error writing mtime")
    49  	}
    50  	stat, ok := fi.Sys().(*syscall.Stat_t)
    51  	if ok {
    52  		// take device and inode into account
    53  		err = binary.Write(h, binary.BigEndian, stat.Ino)
    54  		if err != nil {
    55  			log.Error().Err(err).Msg("error writing inode")
    56  		}
    57  		err = binary.Write(h, binary.BigEndian, stat.Dev)
    58  		if err != nil {
    59  			log.Error().Err(err).Msg("error writing device")
    60  		}
    61  	}
    62  	err = binary.Write(h, binary.BigEndian, fi.Size())
    63  	if err != nil {
    64  		log.Error().Err(err).Msg("error writing size")
    65  	}
    66  	etag := fmt.Sprintf(`"%x"`, h.Sum(nil))
    67  	return fmt.Sprintf("\"%s\"", strings.Trim(etag, "\""))
    68  }
    69  
    70  func (fs *localfs) GetQuota(ctx context.Context, ref *provider.Reference) (uint64, uint64, uint64, error) {
    71  	// TODO quota of which storage space?
    72  	// we could use the logged in user, but when a user has access to multiple storages this falls short
    73  	// for now return quota of root
    74  	stat := syscall.Statfs_t{}
    75  	err := syscall.Statfs(fs.wrap(ctx, "/"), &stat)
    76  	if err != nil {
    77  		return 0, 0, 0, err
    78  	}
    79  	// Total data blocks in filesystem
    80  	total := stat.Blocks * uint64(stat.Bsize)
    81  	// Free blocks available to unprivileged user
    82  	// convert stat.Bavail to uint64 because it returns an int64 on freebsd
    83  	used := (stat.Blocks - uint64(stat.Bavail)) * uint64(stat.Bsize) //nolint:unconvert
    84  	// convert stat.Bavail to uint64 because it returns an int64 on freebsd
    85  	remaining := uint64(stat.Bavail) * uint64(stat.Bsize) //nolint:unconvert
    86  	return total, used, remaining, nil
    87  }