Skip to content

Commit

Permalink
fix quota retrieval in windows systems
Browse files Browse the repository at this point in the history
The quota logic was using a syscall which is not available in windows.
  • Loading branch information
David Christofas committed Feb 22, 2021
1 parent e861f8d commit 0ed12b6
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 21 deletions.
3 changes: 2 additions & 1 deletion changelog/unreleased/ocis-quota.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ Enhancement: quota querying and tree accounting

The ocs api now returns the user quota for the users home storage. Furthermore, the ocis storage driver now reads the quota from the extended attributes of the user home or root node and implements tree size accounting. Finally, ocdav PROPFINDS now handle the `DAV:quota-used-bytes` and `DAV:quote-available-bytes` properties.

https://github.com/cs3org/reva/pull/1405
https://github.com/cs3org/reva/pull/1405
https://github.com/cs3org/reva/pull/1491
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ require (
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221
google.golang.org/grpc v1.35.0
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,8 @@ golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7Ow
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b h1:lAZ0/chPUDWwjqosYR0X4M490zQhMsiJ4K3DbA7o+3g=
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
8 changes: 3 additions & 5 deletions pkg/storage/fs/ocis/ocis.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"path/filepath"
"strconv"
"strings"
"syscall"

userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
Expand Down Expand Up @@ -219,13 +218,12 @@ func (fs *ocisfs) GetQuota(ctx context.Context) (uint64, uint64, error) {
if ri.Opaque != nil && ri.Opaque.Map != nil && ri.Opaque.Map["quota"] != nil && ri.Opaque.Map["quota"].Decoder == "plain" {
quotaStr = string(ri.Opaque.Map["quota"].Value)
}
stat := syscall.Statfs_t{}
err = syscall.Statfs(fs.lu.toInternalPath(node.ID), &stat)

avail, err := fs.getAvailableSize(fs.lu.toInternalPath(node.ID))
if err != nil {
return 0, 0, err
}

total := ri.Size + (stat.Bavail * uint64(stat.Bsize)) // used treesize + available space
total := avail + ri.Size

switch {
case quotaStr == _quotaUncalculated, quotaStr == _quotaUnknown, quotaStr == _quotaUnlimited:
Expand Down
32 changes: 32 additions & 0 deletions pkg/storage/fs/ocis/ocis_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2018-2021 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

// +build !windows

package ocis

import "syscall"

func (fs *ocisfs) getAvailableSize(path string) (uint64, error) {
stat := syscall.Statfs_t{}
err := syscall.Statfs(path, &stat)
if err != nil {
return 0, err
}
return stat.Bavail * uint64(stat.Bsize), nil
}
36 changes: 36 additions & 0 deletions pkg/storage/fs/ocis/ocis_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2018-2021 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

// +build windows

package ocis

import "golang.org/x/sys/windows"

func (fs *ocisfs) getAvailableSize(path string) (uint64, error) {
var free, total, avail uint64
pathPtr, err := windows.UTF16PtrFromString(path)
if err != nil {
return 0, err
}
err = windows.GetDiskFreeSpaceEx(pathPtr, &avail, &total, &free)
if err != nil {
return 0, err
}
return avail, nil
}
15 changes: 0 additions & 15 deletions pkg/storage/utils/localfs/localfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"path"
"strconv"
"strings"
"syscall"
"time"

grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
Expand Down Expand Up @@ -518,20 +517,6 @@ func (fs *localfs) UpdateGrant(ctx context.Context, ref *provider.Reference, g *
return fs.AddGrant(ctx, ref, g)
}

func (fs *localfs) GetQuota(ctx context.Context) (uint64, uint64, error) {
// TODO quota of which storage space?
// we could use the logged in user, but when a user has access to multiple storages this falls short
// for now return quota of root
stat := syscall.Statfs_t{}
err := syscall.Statfs(fs.conf.Root, &stat)
if err != nil {
return 0, 0, err
}
total := stat.Blocks * uint64(stat.Bsize) // Total data blocks in filesystem
used := (stat.Blocks - stat.Bavail) * uint64(stat.Bsize) // Free blocks available to unprivileged user
return total, used, nil
}

func (fs *localfs) CreateReference(ctx context.Context, path string, targetURI *url.URL) error {
if !fs.isShareFolder(ctx, path) {
return errtypes.PermissionDenied("localfs: cannot create references outside the share folder")
Expand Down
14 changes: 14 additions & 0 deletions pkg/storage/utils/localfs/localfs_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,17 @@ func calcEtag(ctx context.Context, fi os.FileInfo) string {
etag := fmt.Sprintf(`"%x"`, h.Sum(nil))
return fmt.Sprintf("\"%s\"", strings.Trim(etag, "\""))
}

func (fs *localfs) GetQuota(ctx context.Context) (uint64, uint64, error) {
// TODO quota of which storage space?
// we could use the logged in user, but when a user has access to multiple storages this falls short
// for now return quota of root
stat := syscall.Statfs_t{}
err := syscall.Statfs(fs.wrap(ctx, "/"), &stat)
if err != nil {
return 0, 0, err
}
total := stat.Blocks * uint64(stat.Bsize) // Total data blocks in filesystem
used := (stat.Blocks - stat.Bavail) * uint64(stat.Bsize) // Free blocks available to unprivileged user
return total, used, nil
}
20 changes: 20 additions & 0 deletions pkg/storage/utils/localfs/localfs_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"strings"

"github.com/cs3org/reva/pkg/appctx"
"golang.org/x/sys/windows"
)

// calcEtag will create an etag based on the md5 of
Expand All @@ -52,3 +53,22 @@ func calcEtag(ctx context.Context, fi os.FileInfo) string {
etag := fmt.Sprintf(`"%x"`, h.Sum(nil))
return fmt.Sprintf("\"%s\"", strings.Trim(etag, "\""))
}

func (fs *localfs) GetQuota(ctx context.Context) (uint64, uint64, error) {
// TODO quota of which storage space?
// we could use the logged in user, but when a user has access to multiple storages this falls short
// for now return quota of root
var free, total, avail uint64

pathPtr, err := windows.UTF16PtrFromString(fs.wrap(ctx, "/"))
if err != nil {
return 0, 0, err
}
err = windows.GetDiskFreeSpaceEx(pathPtr, &avail, &total, &free)
if err != nil {
return 0, 0, err
}

used := total - free
return total, used, nil
}

0 comments on commit 0ed12b6

Please sign in to comment.