From 7c3ce32ee2b625933dcc6b8e1cab631ea502b141 Mon Sep 17 00:00:00 2001 From: Tyler Gill Date: Fri, 22 Sep 2017 00:30:10 -0600 Subject: Add support for the quota reporting and renaming interfaces to the OneDrive backend. To test the quota support, quota information is reported on the command line if it is available. However, the rename support hasn't been tested, since I don't see anything using that functionality yet. --- Duplicati/Library/Backend/OneDrive/OneDrive.cs | 107 ++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 9 deletions(-) (limited to 'Duplicati/Library/Backend') diff --git a/Duplicati/Library/Backend/OneDrive/OneDrive.cs b/Duplicati/Library/Backend/OneDrive/OneDrive.cs index 289dd024a..2b85409bb 100644 --- a/Duplicati/Library/Backend/OneDrive/OneDrive.cs +++ b/Duplicati/Library/Backend/OneDrive/OneDrive.cs @@ -7,7 +7,7 @@ using Duplicati.Library.Interface; namespace Duplicati.Library.Backend { - public class OneDrive : IBackend, IStreamingBackend + public class OneDrive : IBackend, IStreamingBackend, IQuotaEnabledBackend, IRenameEnabledBackend { private const string AUTHID_OPTION = "authid"; @@ -73,11 +73,11 @@ namespace Duplicati.Library.Backend public string upload_location { get; set; } public string type { get; set; } [Newtonsoft.Json.JsonProperty(NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public DateTime created_time { get; set; } + public DateTime? created_time { get; set; } [Newtonsoft.Json.JsonProperty(NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public DateTime updated_time { get; set; } + public DateTime? updated_time { get; set; } [Newtonsoft.Json.JsonProperty(NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long size { get; set; } + public long? size { get; set; } } private class WLID_CreateFolderData @@ -106,13 +106,21 @@ namespace Duplicati.Library.Backend public string locale { get; set; } } + private class WLID_QuotaInfo + { + [Newtonsoft.Json.JsonProperty("quota")] + public long? Quota { get; set; } + [Newtonsoft.Json.JsonProperty("available")] + public long? Available { get; set; } + } + private WLID_FolderItem FindFolder(string folder, string parentfolder = null) { if (string.IsNullOrWhiteSpace(parentfolder)) parentfolder = ROOT_FOLDER_ID; var url = string.Format("{0}/{1}?access_token={2}", WLID_SERVER, string.Format(FOLDER_TEMPLATE, parentfolder), Library.Utility.Uri.UrlEncode(m_oauth.AccessToken)); - var res = m_oauth.GetJSONData(url); + var res = m_oauth.GetJSONData(url, x => x.UserAgent = USER_AGENT); if (res == null || res.data == null) return null; @@ -130,7 +138,7 @@ namespace Duplicati.Library.Backend if (folders.Length == 0) { var url = string.Format("{0}/{1}?access_token={2}", WLID_SERVER, ROOT_FOLDER_ID, Library.Utility.Uri.UrlEncode(m_oauth.AccessToken)); - return m_oauth.GetJSONData(url); + return m_oauth.GetJSONData(url, x => x.UserAgent = USER_AGENT); } WLID_FolderItem cur = null; @@ -214,6 +222,12 @@ namespace Duplicati.Library.Backend return id; } + private WLID_QuotaInfo GetQuotaInfo() + { + var url = string.Format("{0}/me/skydrive/quota?access_token={1}", WLID_SERVER, Library.Utility.Uri.UrlEncode(m_oauth.AccessToken)); + return m_oauth.GetJSONData(url, x => x.UserAgent = USER_AGENT); + } + #region IBackend Members public void Test() @@ -248,7 +262,7 @@ namespace Duplicati.Library.Backend while(count == FILE_LIST_PAGE_SIZE) { var url = string.Format("{0}/{1}?access_token={2}&limit={3}&offset={4}", WLID_SERVER, string.Format(FOLDER_TEMPLATE, FolderID), Library.Utility.Uri.UrlEncode(m_oauth.AccessToken), FILE_LIST_PAGE_SIZE, offset); - var res = m_oauth.GetJSONData(url); + var res = m_oauth.GetJSONData(url, x => x.UserAgent = USER_AGENT); if (res != null && res.data != null) { @@ -257,7 +271,7 @@ namespace Duplicati.Library.Backend { m_fileidCache.Add(r.name, r.id); - var fe = new FileEntry(r.name, r.size, r.updated_time, r.updated_time); + var fe = new FileEntry(r.name, r.size.Value, r.updated_time.Value, r.updated_time.Value); fe.IsFolder = string.Equals(r.type, "folder", StringComparison.OrdinalIgnoreCase); files.Add(fe); } @@ -293,6 +307,7 @@ namespace Duplicati.Library.Backend var id = GetFileID(remotename); var url = string.Format("{0}/{1}?access_token={2}", WLID_SERVER, id, Library.Utility.Uri.UrlEncode(m_oauth.AccessToken)); var req = (HttpWebRequest)WebRequest.Create(url); + req.UserAgent = USER_AGENT; req.Method = "DELETE"; var areq = new Utility.AsyncHttpRequest(req); @@ -354,8 +369,9 @@ namespace Duplicati.Library.Backend { var url = string.Format("{0}/me?access_token={1}", WLID_SERVER, Library.Utility.Uri.UrlEncode(m_oauth.AccessToken)); var req = (HttpWebRequest)WebRequest.Create(url); + req.UserAgent = USER_AGENT; var areq = new Utility.AsyncHttpRequest(req); - + using(var resp = (HttpWebResponse)areq.GetResponse()) using(var rs = areq.GetResponseStream()) using(var tr = new System.IO.StreamReader(rs)) @@ -367,6 +383,79 @@ namespace Duplicati.Library.Backend } } + #region IRenameEnabledBackend + + public void Rename(string oldname, string newname) + { + try + { + try + { + var id = GetFileID(oldname); + var url = string.Format("{0}/{1}?access_token={2}", WLID_SERVER, id, Library.Utility.Uri.UrlEncode(m_oauth.AccessToken)); + var req = (HttpWebRequest)WebRequest.Create(url); + req.UserAgent = USER_AGENT; + req.Method = "PUT"; + + var updateData = new WLID_FolderItem() { name = newname }; + var data = System.Text.Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(updateData)); + req.ContentLength = data.Length; + req.ContentType = "application/json; charset=UTF-8"; + using (var requestStream = req.GetRequestStream()) + requestStream.Write(data, 0, data.Length); + + var areq = new Utility.AsyncHttpRequest(req); + using (var resp = (HttpWebResponse)areq.GetResponse()) + { + if (resp.StatusCode == System.Net.HttpStatusCode.NotFound) + throw new FileMissingException(); + + if ((int)resp.StatusCode < 200 || (int)resp.StatusCode > 299) + throw new ProtocolViolationException(Strings.OneDrive.UnexpectedError(resp.StatusCode, resp.StatusDescription)); + + m_fileidCache[newname] = id; + m_fileidCache.Remove(oldname); + } + } + catch + { + // Since we don't know the state of file IDs, clear the cache + m_fileidCache.Clear(); + + throw; + } + } + catch (System.Net.WebException wex) + { + if (wex.Response is System.Net.HttpWebResponse && ((System.Net.HttpWebResponse)wex.Response).StatusCode == System.Net.HttpStatusCode.NotFound) + throw new FileMissingException(wex); + else + throw; + } + } + + #endregion + + #region IQuotaEnabledBackend Members + + public long TotalQuotaSpace + { + get + { + return this.GetQuotaInfo().Quota ?? -1; + } + } + + public long FreeQuotaSpace + { + get + { + return this.GetQuotaInfo().Available ?? -1; + } + } + + #endregion + #region IStreamingBackend Members public void Put(string remotename, System.IO.Stream stream) -- cgit v1.2.3