Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lockfile fixes for LibreOffice #84

Merged
merged 11 commits into from
Jun 5, 2020
Prev Previous commit
Next Next commit
failing test for weird filenames
  • Loading branch information
jstaf committed Jun 5, 2020
commit b4cd2abeeb1be684d5da7dc433684ffd4b7b2fb1
42 changes: 13 additions & 29 deletions fs/cache.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package fs

import (
"encoding/json"
"errors"
"fmt"
"os"
Expand Down Expand Up @@ -242,12 +241,6 @@ func (c *Cache) DeleteID(id string) {
c.uploads.CancelUpload(id)
}

// only used for parsing
type driveChildren struct {
Children []*Inode `json:"value"`
NextLink string `json:"@odata.nextLink"`
}

// GetChild fetches a named child of an item. Wraps GetChildrenID.
func (c *Cache) GetChild(id string, name string, auth *graph.Auth) (*Inode, error) {
children, err := c.GetChildrenID(id, auth)
Expand Down Expand Up @@ -304,35 +297,26 @@ func (c *Cache) GetChildrenID(id string, auth *graph.Auth) (map[string]*Inode, e
inode.mutex.RUnlock()

// We haven't fetched the children for this item yet, get them from the server.
fetched := make([]*Inode, 0)
for pollURL := graph.ChildrenPathID(id); pollURL != ""; {
body, err := graph.Get(pollURL, auth)
if err != nil {
if graph.IsOffline(err) {
log.WithFields(log.Fields{
"id": id,
}).Warn("We are offline, and no children found in cache. Pretending there are no children.")
return children, nil
}
// something else happened besides being offline
fetched, err := graph.GetItemChildren(id, auth)
if err != nil {
if graph.IsOffline(err) {
log.WithFields(log.Fields{
"err": err,
}).Error("Error while fetching children.")
return nil, err
"id": id,
}).Warn("We are offline, and no children found in cache. Pretending there are no children.")
return children, nil
}
var pollResult driveChildren
json.Unmarshal(body, &pollResult)

// there can be multiple pages of 200 items each (default).
// continue to next interation if we have an @odata.nextLink value
fetched = append(fetched, pollResult.Children...)
pollURL = strings.TrimPrefix(pollResult.NextLink, graph.GraphURL)
// something else happened besides being offline
log.WithFields(log.Fields{
"err": err,
}).Error("Error while fetching children.")
return nil, err
}

inode.mutex.Lock()
inode.children = make([]string, 0)
for _, child := range fetched {
for _, item := range fetched {
// we will always have an id after fetching from the server
child := NewInodeDriveItem(item)
child.cache = c
c.metadata.Store(child.DriveItem.ID, child)

Expand Down
37 changes: 36 additions & 1 deletion fs/graph/drive_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func Mkdir(name string, parentID string, auth *Auth) (*DriveItem, error) {
Folder: &Folder{},
}
bytePayload, _ := json.Marshal(newFolderPost)
resp, err := Post(ChildrenPathID(parentID), auth, bytes.NewReader(bytePayload))
resp, err := Post(childrenPathID(parentID), auth, bytes.NewReader(bytePayload))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -154,3 +154,38 @@ func Rename(itemID string, itemName string, parentID string, auth *Auth) error {
}
return err
}

// only used for parsing
type driveChildren struct {
Children []*DriveItem `json:"value"`
NextLink string `json:"@odata.nextLink"`
}

// this is the internal method that actually fetches an item's children
func getItemChildren(pollURL string, auth *Auth) ([]*DriveItem, error) {
fetched := make([]*DriveItem, 0)
for pollURL != "" {
body, err := Get(pollURL, auth)
if err != nil {
return fetched, err
}
var pollResult driveChildren
json.Unmarshal(body, &pollResult)

// there can be multiple pages of 200 items each (default).
// continue to next interation if we have an @odata.nextLink value
fetched = append(fetched, pollResult.Children...)
pollURL = strings.TrimPrefix(pollResult.NextLink, GraphURL)
}
return fetched, nil
}

// GetItemChildren fetches all children of an item denoted by ID.
func GetItemChildren(id string, auth *Auth) ([]*DriveItem, error) {
return getItemChildren(childrenPathID(id), auth)
}

// GetItemChildrenPath fetches all children of an item denoted by path.
func GetItemChildrenPath(path string, auth *Auth) ([]*DriveItem, error) {
return getItemChildren(childrenPath(path), auth)
}
4 changes: 2 additions & 2 deletions fs/graph/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,15 @@ func ResourcePath(path string) string {
}

// ChildrenPath returns the path to an item's children
func ChildrenPath(path string) string {
func childrenPath(path string) string {
if path == "/" {
return ResourcePath(path) + "/children"
}
return ResourcePath(path) + ":/children"
}

// ChildrenPathID returns the API resource path of an item's children
func ChildrenPathID(id string) string {
func childrenPathID(id string) string {
return "/me/drive/items/" + id + "/children"
}

Expand Down
21 changes: 21 additions & 0 deletions fs/inode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package fs

import (
"io/ioutil"
"path/filepath"
"testing"
"time"

"github.com/hanwen/go-fuse/v2/fuse"
"github.com/jstaf/onedriver/fs/graph"
Expand Down Expand Up @@ -56,3 +58,22 @@ func TestIsDir(t *testing.T) {
t.Fatal("file created with mode 644 not detected as a file")
}
}

// A filename like .~lock.libreoffice-test.docx# will fail to upload unless the
// filename is escaped.
func TestFilenameEscape(t *testing.T) {
fname := `.~lock.libreoffice-test.docx#`
failOnErr(t, ioutil.WriteFile(filepath.Join(TestDir, fname), []byte("argl bargl"), 0644))

time.Sleep(5 * time.Second)

// make sure it made it to the server
children, err := graph.GetItemChildrenPath("/onedriver_tests", auth)
failOnErr(t, err)
for _, child := range children {
if child.Name == fname {
return
}
}
t.Fatalf("Could not find file: \"%s\"", fname)
}