mirror of
https://github.com/rclone/rclone.git
synced 2024-11-29 20:04:52 +01:00
onedrive: ignore OneNote files by default - fixes #211
This commit is contained in:
parent
1d14972e41
commit
d9037fe2be
@ -9,6 +9,9 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
timeFormat = `"` + time.RFC3339 + `"`
|
timeFormat = `"` + time.RFC3339 + `"`
|
||||||
|
|
||||||
|
// PackageTypeOneNote is the package type value for OneNote files
|
||||||
|
PackageTypeOneNote = "oneNote"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error is returned from one drive when things go wrong
|
// Error is returned from one drive when things go wrong
|
||||||
@ -107,6 +110,7 @@ type RemoteItemFacet struct {
|
|||||||
LastModifiedDateTime Timestamp `json:"lastModifiedDateTime"` // Date and time the item was last modified. Read-only.
|
LastModifiedDateTime Timestamp `json:"lastModifiedDateTime"` // Date and time the item was last modified. Read-only.
|
||||||
Folder *FolderFacet `json:"folder"` // Folder metadata, if the item is a folder. Read-only.
|
Folder *FolderFacet `json:"folder"` // Folder metadata, if the item is a folder. Read-only.
|
||||||
File *FileFacet `json:"file"` // File metadata, if the item is a file. Read-only.
|
File *FileFacet `json:"file"` // File metadata, if the item is a file. Read-only.
|
||||||
|
Package *PackageFacet `json:"package"` // If present, indicates that this item is a package instead of a folder or file. Packages are treated like files in some contexts and folders in others. Read-only.
|
||||||
FileSystemInfo *FileSystemInfoFacet `json:"fileSystemInfo"` // File system information on client. Read-write.
|
FileSystemInfo *FileSystemInfoFacet `json:"fileSystemInfo"` // File system information on client. Read-write.
|
||||||
ParentReference *ItemReference `json:"parentReference"` // Parent information, if the item has a parent. Read-write.
|
ParentReference *ItemReference `json:"parentReference"` // Parent information, if the item has a parent. Read-write.
|
||||||
Size int64 `json:"size"` // Size of the item in bytes. Read-only.
|
Size int64 `json:"size"` // Size of the item in bytes. Read-only.
|
||||||
@ -147,6 +151,13 @@ type FileSystemInfoFacet struct {
|
|||||||
type DeletedFacet struct {
|
type DeletedFacet struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PackageFacet indicates that a DriveItem is the top level item
|
||||||
|
// in a "package" or a collection of items that should be treated as a collection instead of individual items.
|
||||||
|
// `oneNote` is the only currently defined value.
|
||||||
|
type PackageFacet struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
// Item represents metadata for an item in OneDrive
|
// Item represents metadata for an item in OneDrive
|
||||||
type Item struct {
|
type Item struct {
|
||||||
ID string `json:"id"` // The unique identifier of the item within the Drive. Read-only.
|
ID string `json:"id"` // The unique identifier of the item within the Drive. Read-only.
|
||||||
@ -170,6 +181,7 @@ type Item struct {
|
|||||||
// Audio *AudioFacet `json:"audio"` // Audio metadata, if the item is an audio file. Read-only.
|
// Audio *AudioFacet `json:"audio"` // Audio metadata, if the item is an audio file. Read-only.
|
||||||
// Video *VideoFacet `json:"video"` // Video metadata, if the item is a video. Read-only.
|
// Video *VideoFacet `json:"video"` // Video metadata, if the item is a video. Read-only.
|
||||||
// Location *LocationFacet `json:"location"` // Location metadata, if the item has location data. Read-only.
|
// Location *LocationFacet `json:"location"` // Location metadata, if the item has location data. Read-only.
|
||||||
|
Package *PackageFacet `json:"package"` // If present, indicates that this item is a package instead of a folder or file. Packages are treated like files in some contexts and folders in others. Read-only.
|
||||||
Deleted *DeletedFacet `json:"deleted"` // Information about the deleted state of the item. Read-only.
|
Deleted *DeletedFacet `json:"deleted"` // Information about the deleted state of the item. Read-only.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,6 +293,24 @@ func (i *Item) GetFolder() *FolderFacet {
|
|||||||
return i.Folder
|
return i.Folder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPackage returns a normalized Package of the item
|
||||||
|
func (i *Item) GetPackage() *PackageFacet {
|
||||||
|
if i.IsRemote() && i.RemoteItem.Package != nil {
|
||||||
|
return i.RemoteItem.Package
|
||||||
|
}
|
||||||
|
return i.Package
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPackageType returns the package type of the item if available,
|
||||||
|
// otherwise ""
|
||||||
|
func (i *Item) GetPackageType() string {
|
||||||
|
pack := i.GetPackage()
|
||||||
|
if pack == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return pack.Type
|
||||||
|
}
|
||||||
|
|
||||||
// GetFile returns a normalized File of the item
|
// GetFile returns a normalized File of the item
|
||||||
func (i *Item) GetFile() *FileFacet {
|
func (i *Item) GetFile() *FileFacet {
|
||||||
if i.IsRemote() && i.RemoteItem.File != nil {
|
if i.IsRemote() && i.RemoteItem.File != nil {
|
||||||
|
@ -226,15 +226,21 @@ func init() {
|
|||||||
Help: "The type of the drive ( personal | business | documentLibrary )",
|
Help: "The type of the drive ( personal | business | documentLibrary )",
|
||||||
Default: "",
|
Default: "",
|
||||||
Advanced: true,
|
Advanced: true,
|
||||||
|
}, {
|
||||||
|
Name: "expose_onenote_files",
|
||||||
|
Help: "If true, OneNote files will show up in directory listing (see docs)",
|
||||||
|
Default: false,
|
||||||
|
Advanced: true,
|
||||||
}},
|
}},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options defines the configuration for this backend
|
// Options defines the configuration for this backend
|
||||||
type Options struct {
|
type Options struct {
|
||||||
ChunkSize fs.SizeSuffix `config:"chunk_size"`
|
ChunkSize fs.SizeSuffix `config:"chunk_size"`
|
||||||
DriveID string `config:"drive_id"`
|
DriveID string `config:"drive_id"`
|
||||||
DriveType string `config:"drive_type"`
|
DriveType string `config:"drive_type"`
|
||||||
|
ExposeOneNoteFiles bool `config:"expose_onenote_files"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fs represents a remote one drive
|
// Fs represents a remote one drive
|
||||||
@ -255,15 +261,16 @@ type Fs struct {
|
|||||||
//
|
//
|
||||||
// Will definitely have info but maybe not meta
|
// Will definitely have info but maybe not meta
|
||||||
type Object struct {
|
type Object struct {
|
||||||
fs *Fs // what this object is part of
|
fs *Fs // what this object is part of
|
||||||
remote string // The remote path
|
remote string // The remote path
|
||||||
hasMetaData bool // whether info below has been set
|
hasMetaData bool // whether info below has been set
|
||||||
size int64 // size of the object
|
isOneNoteFile bool // Whether the object is a OneNote file
|
||||||
modTime time.Time // modification time of the object
|
size int64 // size of the object
|
||||||
id string // ID of the object
|
modTime time.Time // modification time of the object
|
||||||
sha1 string // SHA-1 of the object content
|
id string // ID of the object
|
||||||
quickxorhash string // QuickXorHash of the object content
|
sha1 string // SHA-1 of the object content
|
||||||
mimeType string // Content-Type of object from server (may not be as uploaded)
|
quickxorhash string // QuickXorHash of the object content
|
||||||
|
mimeType string // Content-Type of object from server (may not be as uploaded)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
@ -488,6 +495,9 @@ func (f *Fs) FindLeaf(pathID, leaf string) (pathIDOut string, found bool, err er
|
|||||||
}
|
}
|
||||||
return "", false, err
|
return "", false, err
|
||||||
}
|
}
|
||||||
|
if info.GetPackageType() == api.PackageTypeOneNote {
|
||||||
|
return "", false, errors.New("found OneNote file when looking for folder")
|
||||||
|
}
|
||||||
if info.GetFolder() == nil {
|
if info.GetFolder() == nil {
|
||||||
return "", false, errors.New("found file when looking for folder")
|
return "", false, errors.New("found file when looking for folder")
|
||||||
}
|
}
|
||||||
@ -596,6 +606,11 @@ func (f *Fs) List(dir string) (entries fs.DirEntries, err error) {
|
|||||||
}
|
}
|
||||||
var iErr error
|
var iErr error
|
||||||
_, err = f.listAll(directoryID, false, false, func(info *api.Item) bool {
|
_, err = f.listAll(directoryID, false, false, func(info *api.Item) bool {
|
||||||
|
if !f.opt.ExposeOneNoteFiles && info.GetPackageType() == api.PackageTypeOneNote {
|
||||||
|
fs.Debugf(info.Name, "OneNote file not shown in directory listing")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
remote := path.Join(dir, info.GetName())
|
remote := path.Join(dir, info.GetName())
|
||||||
folder := info.GetFolder()
|
folder := info.GetFolder()
|
||||||
if folder != nil {
|
if folder != nil {
|
||||||
@ -1121,6 +1136,8 @@ func (o *Object) setMetaData(info *api.Item) (err error) {
|
|||||||
o.hasMetaData = true
|
o.hasMetaData = true
|
||||||
o.size = info.GetSize()
|
o.size = info.GetSize()
|
||||||
|
|
||||||
|
o.isOneNoteFile = info.GetPackageType() == api.PackageTypeOneNote
|
||||||
|
|
||||||
// Docs: https://docs.microsoft.com/en-us/onedrive/developer/rest-api/resources/hashes
|
// Docs: https://docs.microsoft.com/en-us/onedrive/developer/rest-api/resources/hashes
|
||||||
//
|
//
|
||||||
// We use SHA1 for onedrive personal and QuickXorHash for onedrive for business
|
// We use SHA1 for onedrive personal and QuickXorHash for onedrive for business
|
||||||
@ -1232,6 +1249,10 @@ func (o *Object) Open(options ...fs.OpenOption) (in io.ReadCloser, err error) {
|
|||||||
if o.id == "" {
|
if o.id == "" {
|
||||||
return nil, errors.New("can't download - no id")
|
return nil, errors.New("can't download - no id")
|
||||||
}
|
}
|
||||||
|
if o.isOneNoteFile {
|
||||||
|
return nil, errors.New("can't open a OneNote file")
|
||||||
|
}
|
||||||
|
|
||||||
fs.FixRangeOption(options, o.size)
|
fs.FixRangeOption(options, o.size)
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
opts := newOptsCall(o.id, "GET", "/content")
|
opts := newOptsCall(o.id, "GET", "/content")
|
||||||
@ -1275,6 +1296,12 @@ func (o *Object) createUploadSession(modTime time.Time) (response *api.CreateUpl
|
|||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
err = o.fs.pacer.Call(func() (bool, error) {
|
err = o.fs.pacer.Call(func() (bool, error) {
|
||||||
resp, err = o.fs.srv.CallJSON(&opts, &createRequest, &response)
|
resp, err = o.fs.srv.CallJSON(&opts, &createRequest, &response)
|
||||||
|
if apiErr, ok := err.(*api.Error); ok {
|
||||||
|
if apiErr.ErrorInfo.Code == "nameAlreadyExists" {
|
||||||
|
// Make the error more user-friendly
|
||||||
|
err = errors.New(err.Error() + " (is it a OneNote file?)")
|
||||||
|
}
|
||||||
|
}
|
||||||
return shouldRetry(resp, err)
|
return shouldRetry(resp, err)
|
||||||
})
|
})
|
||||||
return response, err
|
return response, err
|
||||||
@ -1407,6 +1434,12 @@ func (o *Object) uploadSinglepart(in io.Reader, size int64, modTime time.Time) (
|
|||||||
|
|
||||||
err = o.fs.pacer.Call(func() (bool, error) {
|
err = o.fs.pacer.Call(func() (bool, error) {
|
||||||
resp, err = o.fs.srv.CallJSON(&opts, nil, &info)
|
resp, err = o.fs.srv.CallJSON(&opts, nil, &info)
|
||||||
|
if apiErr, ok := err.(*api.Error); ok {
|
||||||
|
if apiErr.ErrorInfo.Code == "nameAlreadyExists" {
|
||||||
|
// Make the error more user-friendly
|
||||||
|
err = errors.New(err.Error() + " (is it a OneNote file?)")
|
||||||
|
}
|
||||||
|
}
|
||||||
return shouldRetry(resp, err)
|
return shouldRetry(resp, err)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1425,6 +1458,10 @@ func (o *Object) uploadSinglepart(in io.Reader, size int64, modTime time.Time) (
|
|||||||
//
|
//
|
||||||
// The new object may have been created if an error is returned
|
// The new object may have been created if an error is returned
|
||||||
func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (err error) {
|
func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (err error) {
|
||||||
|
if o.hasMetaData && o.isOneNoteFile {
|
||||||
|
return errors.New("can't upload content to a OneNote file")
|
||||||
|
}
|
||||||
|
|
||||||
o.fs.tokenRenewer.Start()
|
o.fs.tokenRenewer.Start()
|
||||||
defer o.fs.tokenRenewer.Stop()
|
defer o.fs.tokenRenewer.Stop()
|
||||||
|
|
||||||
|
@ -165,6 +165,13 @@ system.
|
|||||||
Above this size files will be chunked - must be multiple of 320k. The
|
Above this size files will be chunked - must be multiple of 320k. The
|
||||||
default is 10MB. Note that the chunks will be buffered into memory.
|
default is 10MB. Note that the chunks will be buffered into memory.
|
||||||
|
|
||||||
|
#### --onedrive-expose-onenote-files ####
|
||||||
|
|
||||||
|
By default rclone will hide OneNote files in directory listing because operations like `Open`
|
||||||
|
and `Update` won't work on them. But this behaviour may also prevent you from deleting them.
|
||||||
|
If you want to delete OneNote files or otherwise want them to show up in directory listing,
|
||||||
|
set this flag.
|
||||||
|
|
||||||
### Limitations ###
|
### Limitations ###
|
||||||
|
|
||||||
Note that OneDrive is case insensitive so you can't have a
|
Note that OneDrive is case insensitive so you can't have a
|
||||||
|
Loading…
Reference in New Issue
Block a user