Compare commits

...

11 Commits

Author SHA1 Message Date
Abin
62d83d2df0 Add a flag to toggle OneDrive delta incrementals
This will help us while this is still in development. We should be
able to add in features without affecting anything else.

Once we have it in a more or less stable state this can be removed
completely.
2023-02-22 12:35:04 -08:00
Ashlie Martinez
3edc931d44 Update version to expected version 2023-02-22 12:34:34 -08:00
Ashlie Martinez
e3488b9a5c Merge branch 'main' into 2447-onedrive-folder-order-2 2023-02-22 12:05:46 -08:00
Ashlie Martinez
98b7665249 Update based on reviewer comments 2023-02-22 12:04:56 -08:00
Ashlie Martinez
3f8308cfc1 Update RestoreAndBackup OneDrive tests 2023-02-21 16:04:06 -08:00
Ashlie Martinez
d7ec24d6cd Fixup item comparisons in RestoreAndBackup tests
OneDrive poses a new problem for these tests when permissions are being
checked. Namely, we don't have the permissions for the root directory
(right now), but when we do the backup to check what was restored we
pull the permissions for the root of the subtree we backup (due to
restore as copy behavior).

This commit keeps the framework from comparing metadata on the folder
that is the root of the restored hierarchy.
2023-02-21 16:04:06 -08:00
Ashlie Martinez
4c88617783 Fixup OneDrive tests for how dirmeta is stored 2023-02-21 16:04:06 -08:00
Ashlie Martinez
94f928cc85 Move dirmeta to directory
Store dirmeta files in the directory they refer to instead of the parent
directory.
2023-02-21 16:04:06 -08:00
Ashlie Martinez
9c0566062e Allow creation of empty collections
We've gone back and forth as to whether we should save empty folders or
not. Long-term it seems like we should be. This starts this process (and
simplifies some of the logic). Empty folders will not be able to be
restored without further changes though as they are not directly
accessible through backup details.
2023-02-21 16:04:06 -08:00
Ashlie Martinez
6fe91e254a Expand set of folders selectors match on
Expand the set of folders selectors match on so they match if either
1. the parent path matches (mostly for items using folder selection)
2. the folder path matches
2023-02-21 16:04:06 -08:00
Ashlie Martinez
856c2130e5 Get dir permissions inline
Add code to prepare for storing directory permissions in the directory
itself. This code allows for fetching directory permissions using the
RestoreCollection interface.
2023-02-21 16:04:06 -08:00
11 changed files with 270 additions and 183 deletions

View File

@ -81,6 +81,7 @@ func addOneDriveCommands(cmd *cobra.Command) *cobra.Command {
case createCommand: case createCommand:
c, fs = utils.AddCommand(cmd, oneDriveCreateCmd()) c, fs = utils.AddCommand(cmd, oneDriveCreateCmd())
options.AddFeatureToggle(cmd, options.EnablePermissionsBackup()) options.AddFeatureToggle(cmd, options.EnablePermissionsBackup())
options.AddFeatureToggle(cmd, options.EnableOneDriveDeltaIncrementals())
c.Use = c.Use + " " + oneDriveServiceCommandCreateUseSuffix c.Use = c.Use + " " + oneDriveServiceCommandCreateUseSuffix
c.Example = oneDriveServiceCommandCreateExamples c.Example = oneDriveServiceCommandCreateExamples

View File

@ -16,6 +16,7 @@ func Control() control.Options {
opt.RestorePermissions = restorePermissions opt.RestorePermissions = restorePermissions
opt.ToggleFeatures.DisableIncrementals = disableIncrementals opt.ToggleFeatures.DisableIncrementals = disableIncrementals
opt.ToggleFeatures.EnablePermissionsBackup = enablePermissionsBackup opt.ToggleFeatures.EnablePermissionsBackup = enablePermissionsBackup
opt.ToggleFeatures.EnableOneDriveDeltaIncrementals = enableOneDriveDeltaIncrentals
return opt return opt
} }
@ -59,6 +60,7 @@ func AddRestorePermissionsFlag(cmd *cobra.Command) {
var ( var (
disableIncrementals bool disableIncrementals bool
enablePermissionsBackup bool enablePermissionsBackup bool
enableOneDriveDeltaIncrentals bool
) )
type exposeFeatureFlag func(*pflag.FlagSet) type exposeFeatureFlag func(*pflag.FlagSet)
@ -97,3 +99,16 @@ func EnablePermissionsBackup() func(*pflag.FlagSet) {
cobra.CheckErr(fs.MarkHidden("enable-permissions-backup")) cobra.CheckErr(fs.MarkHidden("enable-permissions-backup"))
} }
} }
// Adds the hidden '--enable-onedrive-delta-incrementals' cli flag which, when
// set, enables delta incrementals for OneDrive.
func EnableOneDriveDeltaIncrementals() func(*pflag.FlagSet) {
return func(fs *pflag.FlagSet) {
fs.BoolVar(
&enableOneDriveDeltaIncrentals,
"enable-onedrive-delta-incrementals",
false,
"Enables delta based incrementals for OneDrive")
cobra.CheckErr(fs.MarkHidden("enable-onedrive-delta-incrementals"))
}
}

View File

@ -704,11 +704,18 @@ func compareOneDriveItem(
t *testing.T, t *testing.T,
expected map[string][]byte, expected map[string][]byte,
item data.Stream, item data.Stream,
dest control.RestoreDestination,
restorePermissions bool, restorePermissions bool,
) { ) bool {
// Skip OneDrive permissions in the folder that used to be the root. We don't
// have a good way to materialize these in the test right now.
if item.UUID() == dest.ContainerName+onedrive.DirMetaFileSuffix {
return false
}
buf, err := io.ReadAll(item.ToReader()) buf, err := io.ReadAll(item.ToReader())
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
return return true
} }
name := item.UUID() name := item.UUID()
@ -721,7 +728,7 @@ func compareOneDriveItem(
err = json.Unmarshal(buf, &itemMeta) err = json.Unmarshal(buf, &itemMeta)
if !assert.NoErrorf(t, err, "unmarshalling retrieved metadata for file %s", name) { if !assert.NoErrorf(t, err, "unmarshalling retrieved metadata for file %s", name) {
return return true
} }
expectedData := expected[name] expectedData := expected[name]
@ -731,12 +738,12 @@ func compareOneDriveItem(
"unexpected metadata file with name %s", "unexpected metadata file with name %s",
name, name,
) { ) {
return return true
} }
err = json.Unmarshal(expectedData, &expectedMeta) err = json.Unmarshal(expectedData, &expectedMeta)
if !assert.NoError(t, err, "unmarshalling expected metadata") { if !assert.NoError(t, err, "unmarshalling expected metadata") {
return return true
} }
// Only compare file names if we're using a version that expects them to be // Only compare file names if we're using a version that expects them to be
@ -747,7 +754,7 @@ func compareOneDriveItem(
if !restorePermissions { if !restorePermissions {
assert.Equal(t, 0, len(itemMeta.Permissions)) assert.Equal(t, 0, len(itemMeta.Permissions))
return return true
} }
testElementsMatch( testElementsMatch(
@ -757,19 +764,19 @@ func compareOneDriveItem(
permissionEqual, permissionEqual,
) )
return return true
} }
var fileData testOneDriveData var fileData testOneDriveData
err = json.Unmarshal(buf, &fileData) err = json.Unmarshal(buf, &fileData)
if !assert.NoErrorf(t, err, "unmarshalling file data for file %s", name) { if !assert.NoErrorf(t, err, "unmarshalling file data for file %s", name) {
return return true
} }
expectedData := expected[fileData.FileName] expectedData := expected[fileData.FileName]
if !assert.NotNil(t, expectedData, "unexpected file with name %s", name) { if !assert.NotNil(t, expectedData, "unexpected file with name %s", name) {
return return true
} }
// OneDrive data items are just byte buffers of the data. Nothing special to // OneDrive data items are just byte buffers of the data. Nothing special to
@ -778,16 +785,22 @@ func compareOneDriveItem(
// Compare against the version with the file name embedded because that's what // Compare against the version with the file name embedded because that's what
// the auto-generated expected data has. // the auto-generated expected data has.
assert.Equal(t, expectedData, buf) assert.Equal(t, expectedData, buf)
return true
} }
// compareItem compares the data returned by backup with the expected data.
// Returns true if a comparison was done else false. Bool return is mostly used
// to exclude OneDrive permissions for the root right now.
func compareItem( func compareItem(
t *testing.T, t *testing.T,
expected map[string][]byte, expected map[string][]byte,
service path.ServiceType, service path.ServiceType,
category path.CategoryType, category path.CategoryType,
item data.Stream, item data.Stream,
dest control.RestoreDestination,
restorePermissions bool, restorePermissions bool,
) { ) bool {
if mt, ok := item.(data.StreamModTime); ok { if mt, ok := item.(data.StreamModTime); ok {
assert.NotZero(t, mt.ModTime()) assert.NotZero(t, mt.ModTime())
} }
@ -806,11 +819,13 @@ func compareItem(
} }
case path.OneDriveService: case path.OneDriveService:
compareOneDriveItem(t, expected, item, restorePermissions) return compareOneDriveItem(t, expected, item, dest, restorePermissions)
default: default:
assert.FailNowf(t, "unexpected service: %s", service.String()) assert.FailNowf(t, "unexpected service: %s", service.String())
} }
return true
} }
func checkHasCollections( func checkHasCollections(
@ -831,7 +846,7 @@ func checkHasCollections(
gotNames = append(gotNames, g.FullPath().String()) gotNames = append(gotNames, g.FullPath().String())
} }
assert.ElementsMatch(t, expectedNames, gotNames) assert.ElementsMatch(t, expectedNames, gotNames, "returned collections")
} }
//revive:disable:context-as-argument //revive:disable:context-as-argument
@ -841,6 +856,7 @@ func checkCollections(
expectedItems int, expectedItems int,
expected map[string]map[string][]byte, expected map[string]map[string][]byte,
got []data.BackupCollection, got []data.BackupCollection,
dest control.RestoreDestination,
restorePermissions bool, restorePermissions bool,
) int { ) int {
//revive:enable:context-as-argument //revive:enable:context-as-argument
@ -850,10 +866,12 @@ func checkCollections(
gotItems := 0 gotItems := 0
for _, returned := range got { for _, returned := range got {
startingItems := gotItems var (
service := returned.FullPath().Service() hasItems bool
category := returned.FullPath().Category() service = returned.FullPath().Service()
expectedColData := expected[returned.FullPath().String()] category = returned.FullPath().Category()
expectedColData = expected[returned.FullPath().String()]
)
// Need to iterate through all items even if we don't expect to find a match // Need to iterate through all items even if we don't expect to find a match
// because otherwise we'll deadlock waiting for GC status. Unexpected or // because otherwise we'll deadlock waiting for GC status. Unexpected or
@ -871,16 +889,19 @@ func checkCollections(
continue continue
} }
hasItems = true
gotItems++ gotItems++
if expectedColData == nil { if expectedColData == nil {
continue continue
} }
compareItem(t, expectedColData, service, category, item, restorePermissions) if !compareItem(t, expectedColData, service, category, item, dest, restorePermissions) {
gotItems--
}
} }
if gotItems != startingItems { if hasItems {
collectionsWithItems = append(collectionsWithItems, returned) collectionsWithItems = append(collectionsWithItems, returned)
} }
} }

View File

@ -175,9 +175,7 @@ func (c *onedriveCollection) withFile(
name+onedrive.DataFileSuffix, name+onedrive.DataFileSuffix,
fileData)) fileData))
case 1: case 1, 2, 3:
fallthrough
case 2:
c.items = append(c.items, onedriveItemWithData( c.items = append(c.items, onedriveItemWithData(
c.t, c.t,
name+onedrive.DataFileSuffix, name+onedrive.DataFileSuffix,
@ -206,12 +204,10 @@ func (c *onedriveCollection) withFolder(
roles []string, roles []string,
) *onedriveCollection { ) *onedriveCollection {
switch c.backupVersion { switch c.backupVersion {
case 0: case 0, 3:
return c return c
case 1: case 1, 2:
fallthrough
case 2:
c.items = append( c.items = append(
c.items, c.items,
onedriveMetadata( onedriveMetadata(
@ -247,15 +243,15 @@ func (c *onedriveCollection) withPermissions(
return c return c
} }
c.items = append( metadata := onedriveMetadata(
c.items,
onedriveMetadata(
c.t, c.t,
name, name,
name+onedrive.DirMetaFileSuffix, name+onedrive.DirMetaFileSuffix,
user, user,
roles), roles)
)
c.items = append(c.items, metadata)
c.aux = append(c.aux, metadata)
return c return c
} }
@ -382,6 +378,10 @@ func (suite *GraphConnectorOneDriveIntegrationSuite) TestRestoreAndBackup_Multip
}, },
{ {
pathElements: folderBPath, pathElements: folderBPath,
perms: permData{
user: suite.secondaryUser,
roles: readPerm,
},
files: []itemData{ files: []itemData{
{ {
name: fileName, name: fileName,
@ -895,6 +895,12 @@ func (suite *GraphConnectorOneDriveIntegrationSuite) TestPermissionsRestoreAndNo
"", "",
nil, nil,
). ).
// Call this to generate a meta file with the folder name that we can
// check.
withPermissions(
"",
nil,
).
collection(), collection(),
}, },
} }

View File

@ -490,7 +490,14 @@ func runBackupAndCompare(
// Pull the data prior to waiting for the status as otherwise it will // Pull the data prior to waiting for the status as otherwise it will
// deadlock. // deadlock.
skipped := checkCollections(t, ctx, totalKopiaItems, expectedData, dcs, config.opts.RestorePermissions) skipped := checkCollections(
t,
ctx,
totalKopiaItems,
expectedData,
dcs,
config.dest,
config.opts.RestorePermissions)
status := backupGC.AwaitStatus() status := backupGC.AwaitStatus()
@ -995,7 +1002,15 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames
// Pull the data prior to waiting for the status as otherwise it will // Pull the data prior to waiting for the status as otherwise it will
// deadlock. // deadlock.
skipped := checkCollections(t, ctx, allItems, allExpectedData, dcs, true) skipped := checkCollections(
t,
ctx,
allItems,
allExpectedData,
dcs,
// Alright to be empty, needed for OneDrive.
control.RestoreDestination{},
true)
status := backupGC.AwaitStatus() status := backupGC.AwaitStatus()
assert.Equal(t, allItems+skipped, status.ObjectCount, "status.ObjectCount") assert.Equal(t, allItems+skipped, status.ObjectCount, "status.ObjectCount")

View File

@ -13,6 +13,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/exp/maps" "golang.org/x/exp/maps"
"github.com/alcionai/corso/src/internal/common/ptr"
"github.com/alcionai/corso/src/internal/connector/graph" "github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/internal/connector/support" "github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/internal/data"
@ -562,8 +563,26 @@ func (c *Collections) UpdateCollections(
return err return err
} }
var (
itemPath path.Path
isFolder = item.GetFolder() != nil || item.GetPackage() != nil
)
if item.GetDeleted() == nil {
name := ptr.Val(item.GetName())
if len(name) == 0 {
return clues.New("non-deleted item with empty name").With("item_id", name)
}
itemPath, err = collectionPath.Append(name, !isFolder)
if err != nil {
return err
}
}
// Skip items that don't match the folder selectors we were given. // Skip items that don't match the folder selectors we were given.
if shouldSkipDrive(ctx, collectionPath, c.matcher, driveName) { if shouldSkipDrive(ctx, itemPath, c.matcher, driveName) &&
shouldSkipDrive(ctx, collectionPath, c.matcher, driveName) {
logger.Ctx(ctx).Infof("Skipping path %s", collectionPath.String()) logger.Ctx(ctx).Infof("Skipping path %s", collectionPath.String())
continue continue
} }
@ -584,13 +603,6 @@ func (c *Collections) UpdateCollections(
// the deleted folder/package. // the deleted folder/package.
delete(newPaths, *item.GetId()) delete(newPaths, *item.GetId())
// TODO(meain): Directory metadata files should be
// moved into the directory instead of having a
// `.dirmeta` file at the same level as the
// directory. This way we can make sure it is moved
// and deleted along with the directory and don't have
// to be handled separately.
if prevPath == nil { if prevPath == nil {
// It is possible that an item was created and // It is possible that an item was created and
// deleted between two delta invocations. In // deleted between two delta invocations. In
@ -616,33 +628,20 @@ func (c *Collections) UpdateCollections(
break break
} }
// Deletions of folders are handled in this case so we may as well start
// off by saving the path.Path of the item instead of just the OneDrive
// parentRef or such.
folderPath, err := collectionPath.Append(*item.GetName(), false)
if err != nil {
logger.Ctx(ctx).Errorw("failed building collection path", "error", err)
return err
}
// Moved folders don't cause delta results for any subfolders nested in // Moved folders don't cause delta results for any subfolders nested in
// them. We need to go through and update paths to handle that. We only // them. We need to go through and update paths to handle that. We only
// update newPaths so we don't accidentally clobber previous deletes. // update newPaths so we don't accidentally clobber previous deletes.
updatePath(newPaths, *item.GetId(), folderPath.String()) updatePath(newPaths, *item.GetId(), itemPath.String())
found, err := updateCollectionPaths(*item.GetId(), c.CollectionMap, folderPath) found, err := updateCollectionPaths(*item.GetId(), c.CollectionMap, itemPath)
if err != nil { if err != nil {
return err return err
} }
if !found { if !found {
// We only create collections for folder that are not
// new. This is so as to not create collections for
// new folders without any files within them.
if prevPath != nil {
col := NewCollection( col := NewCollection(
c.itemClient, c.itemClient,
folderPath, itemPath,
prevPath, prevPath,
driveID, driveID,
c.service, c.service,
@ -654,13 +653,20 @@ func (c *Collections) UpdateCollections(
c.CollectionMap[*item.GetId()] = col c.CollectionMap[*item.GetId()] = col
c.NumContainers++ c.NumContainers++
} }
}
if c.source != OneDriveSource { if c.source != OneDriveSource {
continue continue
} }
fallthrough if col := c.CollectionMap[*item.GetId()]; col != nil {
// Add an entry to fetch permissions into this collection. This assumes
// that OneDrive always returns all folders on the path of an item
// before the item. This seems to hold true for now at least.
collection := col.(*Collection)
if collection.Add(item) {
c.NumItems++
}
}
case item.GetFile() != nil: case item.GetFile() != nil:
if !invalidPrevDelta && item.GetFile() != nil { if !invalidPrevDelta && item.GetFile() != nil {
@ -702,6 +708,11 @@ func (c *Collections) UpdateCollections(
col, found := c.CollectionMap[collectionID] col, found := c.CollectionMap[collectionID]
if !found { if !found {
// TODO(ashmrtn): We should probably tighten the restrictions on this
// and just make it return an error if the collection doesn't already
// exist. Graph seems pretty consistent about returning all folders on
// the path from the root to the item in question. Removing this will
// also ensure we always add an entry to get the folder metadata.
col = NewCollection( col = NewCollection(
c.itemClient, c.itemClient,
collectionPath, collectionPath,
@ -739,14 +750,6 @@ func (c *Collections) UpdateCollections(
if !removed { if !removed {
return clues.New("removing from prev collection").With("item_id", *item.GetId()) return clues.New("removing from prev collection").With("item_id", *item.GetId())
} }
// If that was the only item in that collection and is
// not getting added back, delete the collection
if itemColID != collectionID &&
pcollection.IsEmpty() &&
pcollection.State() == data.NewState {
delete(c.CollectionMap, itemColID)
}
} }
itemCollection[*item.GetId()] = collectionID itemCollection[*item.GetId()] = collectionID
@ -754,12 +757,8 @@ func (c *Collections) UpdateCollections(
if collection.Add(item) { if collection.Add(item) {
c.NumItems++ c.NumItems++
if item.GetFile() != nil {
// This is necessary as we have a fallthrough for
// folders and packages
c.NumFiles++ c.NumFiles++
} }
}
default: default:
return errors.Errorf("item type not supported. item name : %s", *item.GetName()) return errors.Errorf("item type not supported. item name : %s", *item.GetName())
@ -770,6 +769,10 @@ func (c *Collections) UpdateCollections(
} }
func shouldSkipDrive(ctx context.Context, drivePath path.Path, m folderMatcher, driveName string) bool { func shouldSkipDrive(ctx context.Context, drivePath path.Path, m folderMatcher, driveName string) bool {
if drivePath == nil {
return false
}
return !includePath(ctx, m, drivePath) || return !includePath(ctx, m, drivePath) ||
(drivePath.Category() == path.LibrariesCategory && restrictedDirectory == driveName) (drivePath.Category() == path.LibrariesCategory && restrictedDirectory == driveName)
} }

View File

@ -220,7 +220,7 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""), "folder": expectedStatePath(data.NewState, folder),
}, },
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
@ -240,7 +240,7 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""), "package": expectedStatePath(data.NewState, pkg),
}, },
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
@ -299,15 +299,16 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
"subfolder": expectedStatePath(data.NewState, folderSub), "subfolder": expectedStatePath(data.NewState, folderSub),
"folder2": expectedStatePath(data.NewState, folderSub+folder), "folder2": expectedStatePath(data.NewState, folderSub+folder),
}, },
expectedItemCount: 4, expectedItemCount: 5,
expectedFileCount: 2, expectedFileCount: 2,
expectedContainerCount: 3, expectedContainerCount: 3,
// just "folder" isn't added here because the include check is done on the // just "folder" isn't added here because the include check is done on the
// parent path since we only check later if something is a folder or not. // parent path since we only check later if something is a folder or not.
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"subfolder": expectedPath("/folder/subfolder"), "folder": expectedPath(folder),
"folder2": expectedPath("/folder/subfolder/folder"), "subfolder": expectedPath(folderSub),
"folder2": expectedPath(folderSub + folder),
}, },
expectedExcludes: getDelList("fileInFolder", "fileInFolder2"), expectedExcludes: getDelList("fileInFolder", "fileInFolder2"),
}, },
@ -332,12 +333,13 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
"subfolder": expectedStatePath(data.NewState, folderSub), "subfolder": expectedStatePath(data.NewState, folderSub),
"folder2": expectedStatePath(data.NewState, folderSub+folder), "folder2": expectedStatePath(data.NewState, folderSub+folder),
}, },
expectedItemCount: 2, expectedItemCount: 3,
expectedFileCount: 1, expectedFileCount: 1,
expectedContainerCount: 2, expectedContainerCount: 2,
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"folder2": expectedPath("/folder/subfolder/folder"), "subfolder": expectedPath(folderSub),
"folder2": expectedPath(folderSub + folder),
}, },
expectedExcludes: getDelList("fileInFolder2"), expectedExcludes: getDelList("fileInFolder2"),
}, },
@ -359,12 +361,13 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"subfolder": expectedStatePath(data.NewState, folderSub), "subfolder": expectedStatePath(data.NewState, folderSub),
}, },
expectedItemCount: 1, expectedItemCount: 2,
expectedFileCount: 1, expectedFileCount: 1,
expectedContainerCount: 1, expectedContainerCount: 1,
// No child folders for subfolder so nothing here. // No child folders for subfolder so nothing here.
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"subfolder": expectedPath(folderSub),
}, },
expectedExcludes: getDelList("fileInSubfolder"), expectedExcludes: getDelList("fileInSubfolder"),
}, },
@ -375,22 +378,21 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
driveItem("folder", "folder", testBaseDrivePath, "root", false, true, false), driveItem("folder", "folder", testBaseDrivePath, "root", false, true, false),
}, },
inputFolderMap: map[string]string{ inputFolderMap: map[string]string{
"folder": expectedPath("/folder"), "folder": expectedPath(folder),
"subfolder": expectedPath("/folder/subfolder"), "subfolder": expectedPath(folderSub),
}, },
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""), "folder": expectedStatePath(data.NotMovedState, folder),
"folder": expectedStatePath(data.NotMovedState, "/folder"),
}, },
expectedItemCount: 1, expectedItemCount: 1,
expectedFileCount: 0, expectedFileCount: 0,
expectedContainerCount: 2, expectedContainerCount: 1,
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"folder": expectedPath("/folder"), "folder": expectedPath(folder),
"subfolder": expectedPath("/folder/subfolder"), "subfolder": expectedPath(folderSub),
}, },
expectedExcludes: map[string]struct{}{}, expectedExcludes: map[string]struct{}{},
}, },
@ -407,16 +409,15 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""), "folder": expectedStatePath(data.MovedState, folder, "/a-folder"),
"folder": expectedStatePath(data.MovedState, "/folder", "/a-folder"),
}, },
expectedItemCount: 1, expectedItemCount: 1,
expectedFileCount: 0, expectedFileCount: 0,
expectedContainerCount: 2, expectedContainerCount: 1,
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"folder": expectedPath("/folder"), "folder": expectedPath(folder),
"subfolder": expectedPath("/folder/subfolder"), "subfolder": expectedPath(folderSub),
}, },
expectedExcludes: map[string]struct{}{}, expectedExcludes: map[string]struct{}{},
}, },
@ -428,20 +429,19 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
driveItem("folder", "folder", testBaseDrivePath, "root", false, true, false), driveItem("folder", "folder", testBaseDrivePath, "root", false, true, false),
}, },
inputFolderMap: map[string]string{ inputFolderMap: map[string]string{
"folder": expectedPath("/folder"), "folder": expectedPath(folder),
}, },
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""), "folder": expectedStatePath(data.NotMovedState, folder),
"folder": expectedStatePath(data.NotMovedState, "/folder"),
}, },
expectedItemCount: 2, expectedItemCount: 2,
expectedFileCount: 1, expectedFileCount: 1,
expectedContainerCount: 2, expectedContainerCount: 1,
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"folder": expectedPath("/folder"), "folder": expectedPath(folder),
}, },
expectedExcludes: getDelList("file"), expectedExcludes: getDelList("file"),
}, },
@ -457,12 +457,11 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""),
"folder": expectedStatePath(data.NewState, "/folder2"), "folder": expectedStatePath(data.NewState, "/folder2"),
}, },
expectedItemCount: 3, // permissions gets saved twice for folder expectedItemCount: 2,
expectedFileCount: 1, expectedFileCount: 1,
expectedContainerCount: 2, expectedContainerCount: 1,
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"folder": expectedPath("/folder2"), "folder": expectedPath("/folder2"),
@ -480,15 +479,14 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""), "folder": expectedStatePath(data.NewState, folder),
"folder": expectedStatePath(data.NewState, "/folder"),
}, },
expectedItemCount: 2, expectedItemCount: 2,
expectedFileCount: 1, expectedFileCount: 1,
expectedContainerCount: 2, expectedContainerCount: 1,
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"folder": expectedPath("/folder"), "folder": expectedPath(folder),
}, },
expectedExcludes: getDelList("file"), expectedExcludes: getDelList("file"),
}, },
@ -506,16 +504,15 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""), "folder": expectedStatePath(data.MovedState, folder, "/a-folder"),
"folder": expectedStatePath(data.MovedState, "/folder", "/a-folder"),
"subfolder": expectedStatePath(data.MovedState, "/subfolder", "/a-folder/subfolder"), "subfolder": expectedStatePath(data.MovedState, "/subfolder", "/a-folder/subfolder"),
}, },
expectedItemCount: 2, expectedItemCount: 2,
expectedFileCount: 0, expectedFileCount: 0,
expectedContainerCount: 3, expectedContainerCount: 2,
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"folder": expectedPath("/folder"), "folder": expectedPath(folder),
"subfolder": expectedPath("/subfolder"), "subfolder": expectedPath("/subfolder"),
}, },
expectedExcludes: map[string]struct{}{}, expectedExcludes: map[string]struct{}{},
@ -534,16 +531,15 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""), "folder": expectedStatePath(data.MovedState, folder, "/a-folder"),
"folder": expectedStatePath(data.MovedState, "/folder", "/a-folder"),
"subfolder": expectedStatePath(data.MovedState, "/subfolder", "/a-folder/subfolder"), "subfolder": expectedStatePath(data.MovedState, "/subfolder", "/a-folder/subfolder"),
}, },
expectedItemCount: 2, expectedItemCount: 2,
expectedFileCount: 0, expectedFileCount: 0,
expectedContainerCount: 3, expectedContainerCount: 2,
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"folder": expectedPath("/folder"), "folder": expectedPath(folder),
"subfolder": expectedPath("/subfolder"), "subfolder": expectedPath("/subfolder"),
}, },
expectedExcludes: map[string]struct{}{}, expectedExcludes: map[string]struct{}{},
@ -554,6 +550,9 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
driveRootItem("root"), driveRootItem("root"),
driveItem("folder2", "folder2", testBaseDrivePath, "root", false, true, false), driveItem("folder2", "folder2", testBaseDrivePath, "root", false, true, false),
driveItem("itemInFolder2", "itemInFolder2", testBaseDrivePath+"/folder2", "folder2", true, false, false), driveItem("itemInFolder2", "itemInFolder2", testBaseDrivePath+"/folder2", "folder2", true, false, false),
// Need to see the parent folder first (expected since that's what Graph
// consistently returns).
driveItem("folder", "a-folder", testBaseDrivePath, "root", false, true, false),
driveItem("subfolder", "subfolder", testBaseDrivePath+"/a-folder", "folder", false, true, false), driveItem("subfolder", "subfolder", testBaseDrivePath+"/a-folder", "folder", false, true, false),
driveItem( driveItem(
"itemInSubfolder", "itemInSubfolder",
@ -573,14 +572,13 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""), "folder": expectedStatePath(data.MovedState, folder, "/a-folder"),
"folder": expectedStatePath(data.MovedState, "/folder", "/a-folder"),
"folder2": expectedStatePath(data.NewState, "/folder2"), "folder2": expectedStatePath(data.NewState, "/folder2"),
"subfolder": expectedStatePath(data.MovedState, "/folder/subfolder", "/a-folder/subfolder"), "subfolder": expectedStatePath(data.MovedState, folderSub, "/a-folder/subfolder"),
}, },
expectedItemCount: 5, expectedItemCount: 5,
expectedFileCount: 2, expectedFileCount: 2,
expectedContainerCount: 4, expectedContainerCount: 3,
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"folder": expectedPath("/folder"), "folder": expectedPath("/folder"),
@ -604,12 +602,11 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""),
"folder": expectedStatePath(data.MovedState, "/folder2", "/a-folder"), "folder": expectedStatePath(data.MovedState, "/folder2", "/a-folder"),
}, },
expectedItemCount: 3, expectedItemCount: 2,
expectedFileCount: 1, expectedFileCount: 1,
expectedContainerCount: 2, expectedContainerCount: 1,
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"folder": expectedPath("/folder2"), "folder": expectedPath("/folder2"),
@ -678,13 +675,12 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
scope: anyFolder, scope: anyFolder,
expect: assert.NoError, expect: assert.NoError,
expectedCollectionIDs: map[string]statePath{ expectedCollectionIDs: map[string]statePath{
"root": expectedStatePath(data.NotMovedState, ""),
"folder": expectedStatePath(data.DeletedState, folder), "folder": expectedStatePath(data.DeletedState, folder),
"subfolder": expectedStatePath(data.MovedState, "/subfolder", "/folder/subfolder"), "subfolder": expectedStatePath(data.MovedState, "/subfolder", folderSub),
}, },
expectedItemCount: 1, expectedItemCount: 1,
expectedFileCount: 0, expectedFileCount: 0,
expectedContainerCount: 2, expectedContainerCount: 1,
expectedMetadataPaths: map[string]string{ expectedMetadataPaths: map[string]string{
"root": expectedPath(""), "root": expectedPath(""),
"subfolder": expectedPath("/subfolder"), "subfolder": expectedPath("/subfolder"),
@ -748,7 +744,11 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
assert.Equal(t, tt.expectedContainerCount, c.NumContainers, "container count") assert.Equal(t, tt.expectedContainerCount, c.NumContainers, "container count")
for id, sp := range tt.expectedCollectionIDs { for id, sp := range tt.expectedCollectionIDs {
assert.Containsf(t, c.CollectionMap, id, "contains collection with id %s", id) if !assert.Containsf(t, c.CollectionMap, id, "missing collection with id %s", id) {
// Skip collections we don't find so we don't get an NPE.
continue
}
assert.Equalf(t, sp.state, c.CollectionMap[id].State(), "state for collection %s", id) assert.Equalf(t, sp.state, c.CollectionMap[id].State(), "state for collection %s", id)
assert.Equalf(t, sp.curPath, c.CollectionMap[id].FullPath(), "current path for collection %s", id) assert.Equalf(t, sp.curPath, c.CollectionMap[id].FullPath(), "current path for collection %s", id)
assert.Equalf(t, sp.prevPath, c.CollectionMap[id].PreviousPath(), "prev path for collection %s", id) assert.Equalf(t, sp.prevPath, c.CollectionMap[id].PreviousPath(), "prev path for collection %s", id)
@ -1294,8 +1294,7 @@ func (suite *OneDriveCollectionsSuite) TestGet() {
driveID1: {}, driveID1: {},
}, },
expectedCollections: map[string]map[data.CollectionState][]string{ expectedCollections: map[string]map[data.CollectionState][]string{
folderPath1: {data.NewState: {"file"}}, folderPath1: {data.NewState: {"folder", "file"}},
rootFolderPath1: {data.NotMovedState: {"folder"}},
}, },
expectedDeltaURLs: map[string]string{ expectedDeltaURLs: map[string]string{
driveID1: delta, driveID1: delta,
@ -1329,8 +1328,7 @@ func (suite *OneDriveCollectionsSuite) TestGet() {
driveID1: {}, driveID1: {},
}, },
expectedCollections: map[string]map[data.CollectionState][]string{ expectedCollections: map[string]map[data.CollectionState][]string{
folderPath1: {data.NewState: {"file"}}, folderPath1: {data.NewState: {"folder", "file"}},
rootFolderPath1: {data.NotMovedState: {"folder"}},
}, },
expectedDeltaURLs: map[string]string{ expectedDeltaURLs: map[string]string{
driveID1: delta, driveID1: delta,
@ -1364,7 +1362,8 @@ func (suite *OneDriveCollectionsSuite) TestGet() {
driveID1: {}, driveID1: {},
}, },
expectedCollections: map[string]map[data.CollectionState][]string{ expectedCollections: map[string]map[data.CollectionState][]string{
rootFolderPath1: {data.NotMovedState: {"folder", "file"}}, rootFolderPath1: {data.NotMovedState: {"file"}},
folderPath1: {data.NewState: {"folder"}},
}, },
expectedDeltaURLs: map[string]string{ expectedDeltaURLs: map[string]string{
driveID1: delta, driveID1: delta,
@ -1397,8 +1396,7 @@ func (suite *OneDriveCollectionsSuite) TestGet() {
driveID1: {}, driveID1: {},
}, },
expectedCollections: map[string]map[data.CollectionState][]string{ expectedCollections: map[string]map[data.CollectionState][]string{
folderPath1: {data.NewState: {"file"}}, folderPath1: {data.NewState: {"folder", "file"}},
rootFolderPath1: {data.NotMovedState: {"folder"}},
}, },
expectedDeltaURLs: map[string]string{}, expectedDeltaURLs: map[string]string{},
expectedFolderPaths: map[string]map[string]string{}, expectedFolderPaths: map[string]map[string]string{},
@ -1432,8 +1430,7 @@ func (suite *OneDriveCollectionsSuite) TestGet() {
driveID1: {}, driveID1: {},
}, },
expectedCollections: map[string]map[data.CollectionState][]string{ expectedCollections: map[string]map[data.CollectionState][]string{
folderPath1: {data.NewState: {"file", "file2"}}, folderPath1: {data.NewState: {"folder", "file", "file2"}},
rootFolderPath1: {data.NotMovedState: {"folder"}},
}, },
expectedDeltaURLs: map[string]string{ expectedDeltaURLs: map[string]string{
driveID1: delta, driveID1: delta,
@ -1480,10 +1477,8 @@ func (suite *OneDriveCollectionsSuite) TestGet() {
driveID2: {}, driveID2: {},
}, },
expectedCollections: map[string]map[data.CollectionState][]string{ expectedCollections: map[string]map[data.CollectionState][]string{
folderPath1: {data.NewState: {"file"}}, folderPath1: {data.NewState: {"folder", "file"}},
folderPath2: {data.NewState: {"file2"}}, folderPath2: {data.NewState: {"folder2", "file2"}},
rootFolderPath1: {data.NotMovedState: {"folder"}},
rootFolderPath2: {data.NotMovedState: {"folder2"}},
}, },
expectedDeltaURLs: map[string]string{ expectedDeltaURLs: map[string]string{
driveID1: delta, driveID1: delta,
@ -1579,8 +1574,8 @@ func (suite *OneDriveCollectionsSuite) TestGet() {
}, },
errCheck: assert.NoError, errCheck: assert.NoError,
expectedCollections: map[string]map[data.CollectionState][]string{ expectedCollections: map[string]map[data.CollectionState][]string{
expectedPath1(""): {data.NotMovedState: {"file", "folder"}}, expectedPath1(""): {data.NotMovedState: {"file"}},
expectedPath1("/folder"): {data.NewState: {"file2"}}, expectedPath1("/folder"): {data.NewState: {"folder", "file2"}},
}, },
expectedDeltaURLs: map[string]string{ expectedDeltaURLs: map[string]string{
driveID1: delta, driveID1: delta,
@ -1621,8 +1616,8 @@ func (suite *OneDriveCollectionsSuite) TestGet() {
driveID1: {}, driveID1: {},
}, },
expectedCollections: map[string]map[data.CollectionState][]string{ expectedCollections: map[string]map[data.CollectionState][]string{
expectedPath1(""): {data.NotMovedState: {"file", "folder"}}, expectedPath1(""): {data.NotMovedState: {"file"}},
expectedPath1("/folder"): {data.NewState: {"file2"}}, expectedPath1("/folder"): {data.NewState: {"folder", "file2"}},
}, },
expectedDeltaURLs: map[string]string{ expectedDeltaURLs: map[string]string{
driveID1: delta, driveID1: delta,
@ -1662,9 +1657,8 @@ func (suite *OneDriveCollectionsSuite) TestGet() {
}, },
}, },
expectedCollections: map[string]map[data.CollectionState][]string{ expectedCollections: map[string]map[data.CollectionState][]string{
expectedPath1(""): {data.NotMovedState: {"folder2"}},
expectedPath1("/folder"): {data.DeletedState: {}}, expectedPath1("/folder"): {data.DeletedState: {}},
expectedPath1("/folder2"): {data.NewState: {"file"}}, expectedPath1("/folder2"): {data.NewState: {"folder2", "file"}},
}, },
expectedDeltaURLs: map[string]string{ expectedDeltaURLs: map[string]string{
driveID1: delta, driveID1: delta,
@ -1704,8 +1698,7 @@ func (suite *OneDriveCollectionsSuite) TestGet() {
}, },
}, },
expectedCollections: map[string]map[data.CollectionState][]string{ expectedCollections: map[string]map[data.CollectionState][]string{
expectedPath1(""): {data.NotMovedState: {"folder2"}}, expectedPath1("/folder"): {data.NewState: {"folder2", "file"}},
expectedPath1("/folder"): {data.NewState: {"file"}},
}, },
expectedDeltaURLs: map[string]string{ expectedDeltaURLs: map[string]string{
driveID1: delta, driveID1: delta,
@ -1835,9 +1828,9 @@ func (suite *OneDriveCollectionsSuite) TestGet() {
t, t,
test.expectedCollections[folderPath][baseCol.State()], test.expectedCollections[folderPath][baseCol.State()],
itemIDs, itemIDs,
"items in collection %s", "state: %d, path: %s",
folderPath, baseCol.State(),
) folderPath)
assert.Equal(t, test.doNotMergeItems, baseCol.DoNotMergeItems(), "DoNotMergeItems") assert.Equal(t, test.doNotMergeItems, baseCol.DoNotMergeItems(), "DoNotMergeItems")
} }

View File

@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"math"
"runtime/trace" "runtime/trace"
"sort" "sort"
"strings" "strings"
@ -39,9 +38,11 @@ const (
// versionWithNameInMeta points to the backup format version where we begin // versionWithNameInMeta points to the backup format version where we begin
// storing files in kopia with their item ID instead of their OneDrive file // storing files in kopia with their item ID instead of their OneDrive file
// name. // name.
// TODO(ashmrtn): Update this to a real value when we merge the file name versionWithNameInMeta = 5
// change. Set to MAXINT for now to keep the if-check using it working. // versionWithDataAndMetaFilesInDir moves the .dirmeta entries to the
versionWithNameInMeta = math.MaxInt // directory they belong to instead of being in the parent of the directory
// they belong to.
versionWithDataAndMetaFilesInDir = 3
) )
func getParentPermissions( func getParentPermissions(
@ -66,12 +67,14 @@ func getParentPermissions(
} }
func getParentAndCollectionPermissions( func getParentAndCollectionPermissions(
ctx context.Context,
drivePath *path.DrivePath, drivePath *path.DrivePath,
collectionPath path.Path, dc data.RestoreCollection,
permissions map[string][]UserPermission, permissions map[string][]UserPermission,
backupVersion int,
restorePerms bool, restorePerms bool,
) ([]UserPermission, []UserPermission, error) { ) ([]UserPermission, []UserPermission, error) {
if !restorePerms { if !restorePerms || backupVersion < versionWithDataAndMetaFiles {
return nil, nil, nil return nil, nil, nil
} }
@ -79,6 +82,7 @@ func getParentAndCollectionPermissions(
err error err error
parentPerms []UserPermission parentPerms []UserPermission
colPerms []UserPermission colPerms []UserPermission
collectionPath = dc.FullPath()
) )
// Only get parent permissions if we're not restoring the root. // Only get parent permissions if we're not restoring the root.
@ -94,12 +98,25 @@ func getParentAndCollectionPermissions(
} }
} }
// TODO(ashmrtn): For versions after this pull the permissions from the if backupVersion < versionWithDataAndMetaFilesInDir {
// current collection with Fetch().
colPerms, err = getParentPermissions(collectionPath, permissions) colPerms, err = getParentPermissions(collectionPath, permissions)
if err != nil { if err != nil {
return nil, nil, clues.Wrap(err, "getting collection permissions") return nil, nil, clues.Wrap(err, "getting collection permissions")
} }
} else if len(drivePath.Folders) > 0 {
// Root folder doesn't have a metadata file associated with it.
folders := collectionPath.Folders()
meta, err := fetchAndReadMetadata(
ctx,
dc,
folders[len(folders)-1]+DirMetaFileSuffix)
if err != nil {
return nil, nil, clues.Wrap(err, "collection permissions")
}
colPerms = meta.Permissions
}
return parentPerms, colPerms, nil return parentPerms, colPerms, nil
} }
@ -223,9 +240,11 @@ func RestoreCollection(
"destination", restoreFolderElements) "destination", restoreFolderElements)
parentPerms, colPerms, err := getParentAndCollectionPermissions( parentPerms, colPerms, err := getParentAndCollectionPermissions(
ctx,
drivePath, drivePath,
dc.FullPath(), dc,
parentPermissions, parentPermissions,
backupVersion,
restorePerms) restorePerms)
if err != nil { if err != nil {
errUpdater(directory.String(), err) errUpdater(directory.String(), err)
@ -330,7 +349,10 @@ func RestoreCollection(
// RestoreOp, so we still need to handle them in some way. // RestoreOp, so we still need to handle them in some way.
continue continue
} else if strings.HasSuffix(name, DirMetaFileSuffix) { } else if strings.HasSuffix(name, DirMetaFileSuffix) {
if !restorePerms { // Only the versionWithDataAndMetaFiles needed to deserialize the
// permission for child folders here. Later versions can request
// permissions inline when processing the collection.
if !restorePerms || backupVersion >= versionWithDataAndMetaFilesInDir {
continue continue
} }

View File

@ -289,6 +289,11 @@ func (op *BackupOperation) do(
// checker to see if conditions are correct for incremental backup behavior such as // checker to see if conditions are correct for incremental backup behavior such as
// retrieving metadata like delta tokens and previous paths. // retrieving metadata like delta tokens and previous paths.
func useIncrementalBackup(sel selectors.Selector, opts control.Options) bool { func useIncrementalBackup(sel selectors.Selector, opts control.Options) bool {
// TODO(meain): remove this once we stabilize delta incrementals for OneDrive
if sel.Service == selectors.ServiceOneDrive {
return opts.ToggleFeatures.EnableOneDriveDeltaIncrementals
}
// Delta-based incrementals currently only supported for Exchange // Delta-based incrementals currently only supported for Exchange
if sel.Service != selectors.ServiceExchange { if sel.Service != selectors.ServiceExchange {
return false return false

View File

@ -14,7 +14,7 @@ import (
"github.com/alcionai/corso/src/pkg/selectors" "github.com/alcionai/corso/src/pkg/selectors"
) )
const Version = 2 const Version = 5
// Backup represents the result of a backup operation // Backup represents the result of a backup operation
type Backup struct { type Backup struct {

View File

@ -80,4 +80,10 @@ type Toggles struct {
// permissions. Permission metadata increases graph api call count, // permissions. Permission metadata increases graph api call count,
// so disabling their retrieval when not needed is advised. // so disabling their retrieval when not needed is advised.
EnablePermissionsBackup bool `json:"enablePermissionsBackup,omitempty"` EnablePermissionsBackup bool `json:"enablePermissionsBackup,omitempty"`
// EnableOneDriveDeltaIncrementals is used to enable OneDrive
// delta incrementals. It is set to false by default as OneDrive
// delta incrementals is still in development. This flag works
// independent of DisableIncrementals.
EnableOneDriveDeltaIncrementals bool `json:"enableOneDriveDeltaIncrementals,omitempty"`
} }