示例#1
0
        /// <summary>
        /// Move file in another space on the server.
        /// </summary>
        /// <param name="file">File info to move.</param>
        /// <param name="destinationPath">Destination path on the server.</param>
        /// <returns>True or false operation result.</returns>
        public async Task <bool> MoveAsync(File file, string destinationPath)
        {
            var link = await _linkManager.GetItemLink(file.FullPath, false);

            if (link != null)
            {
                var remapped = await _linkManager.RemapLink(link, destinationPath);

                if (remapped)
                {
                    _itemCache.Invalidate(file.Path, destinationPath);
                }
                return(remapped);
            }

            var qry = file.Files
                      .AsParallel()
                      .WithDegreeOfParallelism(Math.Min(MaxInnerParallelRequests, file.Files.Count))
                      .Select(async pfile =>
            {
                var moveres = await Account.RequestRepo.Move(pfile.FullPath, destinationPath);
                _itemCache.Forget(file.Path, pfile.FullPath);
                return(moveres);
            });

            _itemCache.Forget(file.Path, file.FullPath);
            _itemCache.Invalidate(destinationPath);

            bool res = (await Task.WhenAll(qry))
                       .All(r => r.IsSuccess);

            return(res);
        }
        public async Task <Stream> Create(File file, FileUploadedDelegate onUploaded = null, bool discardEncryption = false)
        {
            if (!(await _cloud.GetItemAsync(file.Path, Cloud.ItemType.Folder) is Folder folder))
            {
                throw new DirectoryNotFoundException(file.Path);
            }

            Stream stream;

            bool cryptRequired = _cloud.IsFileExists(CryptFileInfo.FileName, WebDavPath.GetParents(folder.FullPath).ToList()).Any();

            if (cryptRequired && !discardEncryption)
            {
                if (!_cloud.Account.Credentials.CanCrypt)
                {
                    throw new Exception($"Cannot upload {file.FullPath} to crypt folder without additional password!");
                }

                // #142 remove crypted file parts if size changed
                var remoteFile = folder.Files.FirstOrDefault(f => f.FullPath == file.FullPath);
                if (remoteFile != null)
                {
                    await _cloud.Remove(remoteFile);
                }

                stream = GetCryptoStream(file, onUploaded);
            }
            else
            {
                stream = GetPlainStream(file, onUploaded);
            }

            return(stream);
        }
        private Stream GetCryptoStream(File file, FileUploadedDelegate onUploaded)
        {
            var info = CryptoUtil.GetCryptoKeyAndSalt(_cloud.Account.Credentials.PasswordCrypt);
            var xts  = XtsAes256.Create(info.Key, info.IV);

            file.ServiceInfo.CryptInfo = new CryptInfo
            {
                PublicKey = new CryptoKeyInfo {
                    Salt = info.Salt, IV = info.IV
                },
                AlignBytes = (uint)(file.Size % XTSWriteOnlyStream.BlockSize != 0
                    ? XTSWriteOnlyStream.BlockSize - file.Size % XTSWriteOnlyStream.BlockSize
                    : 0)
            };

            var size = file.OriginalSize % XTSWriteOnlyStream.BlockSize == 0
                ? file.OriginalSize.DefaultValue
                : (file.OriginalSize / XTSWriteOnlyStream.BlockSize + 1) * XTSWriteOnlyStream.BlockSize;

            var ustream = new SplittedUploadStream(file.FullPath, _cloud, size, false, file.ServiceInfo.CryptInfo);

            if (onUploaded != null)
            {
                ustream.FileUploaded += onUploaded;
            }
            // ReSharper disable once RedundantArgumentDefaultValue
            var encustream = new XTSWriteOnlyStream(ustream, xts, XTSWriteOnlyStream.DefaultSectorSize);

            return(encustream);
        }
示例#4
0
        private Stream CreateXTSStream(File file, long?start = null, long?end = null)
        {
            var pub = CryptoUtil.GetCryptoPublicInfo(_cloud, file);
            var key = CryptoUtil.GetCryptoKey(_cloud.Account.Credentials.PasswordCrypt, pub.Salt);
            var xts = XtsAes256.Create(key, pub.IV);

            long fileLength      = file.OriginalSize;
            long requestedOffset = start ?? 0;
            long requestedEnd    = end ?? fileLength;

            long alignedOffset = requestedOffset / XTSSectorSize * XTSSectorSize;
            long alignedEnd    = requestedEnd % XTSBlockSize == 0
                ? requestedEnd
                : (requestedEnd / XTSBlockSize + 1) * XTSBlockSize;

            if (alignedEnd == 0)
            {
                alignedEnd = 16;
            }

            var downStream = _cloud.Account.RequestRepo.GetDownloadStream(file, alignedOffset, alignedEnd);

            ulong startSector = (ulong)alignedOffset / XTSSectorSize;
            int   trimStart   = (int)(requestedOffset - alignedOffset);
            uint  trimEnd     = alignedEnd == fileLength
                ? file.ServiceInfo.CryptInfo.AlignBytes
                : (uint)(alignedEnd - requestedEnd);

            var xtsStream = new XTSReadOnlyStream(downStream, xts, XTSSectorSize, startSector, trimStart, trimEnd);

            return(xtsStream);
        }
        public LocalStoreItem(File fileInfo, bool isWritable, LocalStore store)
        {
            _store = store;

            _fileInfo = fileInfo;

            IsWritable = isWritable;
        }
示例#6
0
        public async Task  Unpublish(File file)
        {
            foreach (var innerFile in file.Files)
            {
                await Unpublish(innerFile.GetPublicLinks(this).First().Uri, innerFile.FullPath);

                innerFile.PublicLinks.Clear();
            }
            _itemCache.Invalidate(file.FullPath, file.Path);
        }
示例#7
0
 public async Task <PublishInfo> Publish(IEntry entry, bool makeShareFile = true,
                                         bool generateDirectVideoLink     = false, bool makeM3UFile = false, SharedVideoResolution videoResolution = SharedVideoResolution.All)
 {
     return(entry switch
     {
         null => throw new ArgumentNullException(nameof(entry)),
         File file => await Publish(file, makeShareFile, generateDirectVideoLink, makeM3UFile, videoResolution),
         Folder folder => await Publish(folder, makeShareFile),
         _ => throw new Exception($"Unknow entry type, type = {entry.GetType()},path = {entry.FullPath}")
     });
示例#8
0
        public async Task  Unpublish(File file)
        {
            foreach (var innerFile in file.Files)
            {
                await Unpublish(innerFile.GetPublicLink(this));

                innerFile.PublicLink = string.Empty;
            }
            _itemCache.Invalidate(file.FullPath, file.Path);
        }
        private Stream GetPlainStream(File file, FileUploadedDelegate onUploaded)
        {
            var stream = new SplittedUploadStream(file.FullPath, _cloud, file.Size);

            if (onUploaded != null)
            {
                stream.FileUploaded += onUploaded;
            }
            return(stream);
        }
示例#10
0
        public Stream Create(File file, long?start = null, long?end = null)
        {
            if (file.ServiceInfo.IsCrypted)
            {
                return(CreateXTSStream(file, start, end));
            }

            //return new DownloadStream(file, _cloud.CloudApi, start, end);
            var stream = _cloud.Account.RequestRepo.GetDownloadStream(file, start, end);

            return(stream);
        }
示例#11
0
        /// <summary>
        /// Remove the file on server.
        /// </summary>
        /// <param name="file">File info.</param>
        /// <param name="removeShareDescription">Also remove share description file (.share.wdmrc)</param>
        /// <param name="doInvalidateCache"></param>
        /// <returns>True or false operation result.</returns>
        public virtual async Task <bool> Remove(File file, bool removeShareDescription = true, bool doInvalidateCache = true)
        {
            // remove all parts if file splitted
            var qry = file.Files
                      .AsParallel()
                      .WithDegreeOfParallelism(Math.Min(MaxInnerParallelRequests, file.Files.Count))
                      .Select(async pfile =>
            {
                var removed = await Remove(pfile.FullPath);
                return(removed);
            });
            bool res = (await Task.WhenAll(qry)).All(r => r);

            if (res)
            {
                //unshare master item
                if (file.Name.EndsWith(PublishInfo.SharedFilePostfix))
                {
                    var mpath = WebDavPath.Clean(file.FullPath.Substring(0, file.FullPath.Length - PublishInfo.SharedFilePostfix.Length));
                    var item  = await GetItemAsync(mpath);


                    if (item is Folder folder)
                    {
                        await Unpublish(folder.GetPublicLink(this));
                    }
                    else if (item is File ifile)
                    {
                        await Unpublish(ifile);
                    }
                }
                else
                {
                    //remove share description (.wdmrc.share)
                    if (removeShareDescription)
                    {
                        if (await GetItemAsync(file.FullPath + PublishInfo.SharedFilePostfix) is File sharefile)
                        {
                            await Remove(sharefile, false);
                        }
                    }
                }
            }


            if (doInvalidateCache)
            {
                _itemCache.Invalidate(file.Path, file.FullPath);
            }

            return(res);
        }
示例#12
0
        public Task <StoreItemResult> CreateItemAsync(string name, bool overwrite, IHttpContext httpContext)
        {
            if (!IsWritable)
            {
                return(Task.FromResult(new StoreItemResult(DavStatusCode.PreconditionFailed)));
            }

            var destinationPath = FullPath + "/" + name;

            var size = httpContext.Request.ContentLength();

            var f = new File(destinationPath, size);

            return(Task.FromResult(new StoreItemResult(DavStatusCode.Created, new LocalStoreItem(f, IsWritable, _store))));
        }
示例#13
0
        /// <summary>
        /// Rename file on the server.
        /// </summary>
        /// <param name="file">Source file info.</param>
        /// <param name="newFileName">New file name.</param>
        /// <returns>True or false operation result.</returns>
        public async Task <bool> Rename(File file, string newFileName)
        {
            var result = await Rename(file.FullPath, newFileName).ConfigureAwait(false);

            if (file.Files.Count > 1)
            {
                foreach (var splitFile in file.Parts)
                {
                    string newSplitName = newFileName + splitFile.ServiceInfo.ToString(false);
                    await Rename(splitFile.FullPath, newSplitName).ConfigureAwait(false);
                }
            }

            return(result);
        }
        public Task <StoreItemResult> CreateItemAsync(string name, bool overwrite, IHttpContext httpContext)
        {
            if (!IsWritable)
            {
                return(Task.FromResult(new StoreItemResult(DavStatusCode.PreconditionFailed)));
            }

            var destinationPath = FullPath + "/" + name;

            DavStatusCode result = DavStatusCode.Created;

            var size = httpContext.Request.ContentLength();

            var f = new File(destinationPath, size, null);

            return(Task.FromResult(new StoreItemResult(result, new MailruStoreItem(LockingManager, f, IsWritable))));
        }
示例#15
0
        private void FillWithULinks(Folder folder)
        {
            if (!folder.IsChildsLoaded)
            {
                return;
            }

            var flinks = _linkManager.GetItems(folder.FullPath);

            if (flinks.Any())
            {
                foreach (var flink in flinks)
                {
                    string linkpath = WebDavPath.Combine(folder.FullPath, flink.Name);

                    if (!flink.IsFile)
                    {
                        folder.Folders.Add(new Folder(0, linkpath)
                        {
                            CreationTimeUtc = flink.CreationDate ?? DateTime.MinValue
                        });
                    }
                    else
                    {
                        if (folder.Files.All(inf => inf.FullPath != linkpath))
                        {
                            var newfile = new File(linkpath, flink.Size);
                            {
                                newfile.PublicLinks.Add(new PublicLinkInfo(flink.Href));
                            }

                            if (flink.CreationDate != null)
                            {
                                newfile.LastWriteTimeUtc = flink.CreationDate.Value;
                            }
                            folder.Files.Add(newfile);
                        }
                    }
                }
            }

            foreach (var childFolder in folder.Folders)
            {
                FillWithULinks(childFolder);
            }
        }
示例#16
0
        private void Initialize()
        {
            long allowedSize = _maxFileSize; //TODO: make it right //- BytesCount(_file.Name);

            _performAsSplitted = _size > allowedSize || _cryptInfo != null;
            _origfile          = new File(_destinationPath, _size, null);

            if (!_performAsSplitted) // crypted are performed alike splitted file
            {
                _files.Add(_origfile);
            }
            else
            {
                var sinfo = new FilenameServiceInfo
                {
                    CleanName = _origfile.Name,
                    CryptInfo = _cryptInfo,
                    SplitInfo = new FileSplitInfo {
                        IsHeader = false
                    }
                };


                int nfiles = (int)(_size / allowedSize + 1);
                if (nfiles > 999)
                {
                    throw new OverflowException("Cannot upload more than 999 file parts");
                }

                //TODO: move file splitting in File class
                for (int i = 1; i <= nfiles; i++)
                {
                    sinfo.SplitInfo.PartNumber = i;
                    sinfo.CryptInfo            = i != nfiles ? null : _cryptInfo;

                    var f = new File($"{_origfile.FullPath}{sinfo}",
                                     i != nfiles ? allowedSize : _size % allowedSize,
                                     null);
                    _files.Add(f);
                }
            }

            NextFile();
        }
示例#17
0
        public async Task <PublishInfo> Publish(File file, bool makeShareFile = true,
                                                bool generateDirectVideoLink  = false, bool makeM3UFile = false, SharedVideoResolution videoResolution = SharedVideoResolution.All)
        {
            if (file.Files.Count > 1 && (generateDirectVideoLink || makeM3UFile))
            {
                throw new ArgumentException($"Cannot generate direct video link for splitted file {file.FullPath}");
            }

            foreach (var innerFile in file.Files)
            {
                var url = await Publish(innerFile.FullPath);

                innerFile.PublicLinks.Clear();
                innerFile.PublicLinks.Add(new PublicLinkInfo(url));
            }
            var info = file.ToPublishInfo(this, generateDirectVideoLink, videoResolution);

            if (makeShareFile)
            {
                string path = $"{file.FullPath}{PublishInfo.SharedFilePostfix}";
                UploadFileJson(path, info)
                .ThrowIf(r => !r, r => new Exception($"Cannot upload JSON file, path = {path}"));
            }


            if (makeM3UFile)
            {
                string path    = $"{file.FullPath}{PublishInfo.PlaylistFilePostfix}";
                var    content = new StringBuilder();
                {
                    content.Append("#EXTM3U\r\n");
                    foreach (var item in info.Items)
                    {
                        content.Append($"#EXTINF:-1,{WebDavPath.Name(item.Path)}\r\n");
                        content.Append($"{item.PlaylistUrl}\r\n");
                    }
                }
                UploadFile(path, content.ToString())
                .ThrowIf(r => !r, r => new Exception($"Cannot upload JSON file, path = {path}"));
            }

            return(info);
        }
示例#18
0
 public LocalStoreItem(ILockingManager lockingManager, File fileInfo, bool isWritable)
 {
     LockingManager = lockingManager;
     _fileInfo      = fileInfo;
     IsWritable     = isWritable;
 }
示例#19
0
        /// <summary>
        /// Copy file to another path.
        /// </summary>
        /// <param name="file">Source file info.</param>
        /// <param name="destinationPath">Destination path.</param>
        /// <param name="newname">Rename target file.</param>
        /// <returns>True or false operation result.</returns>
        public async Task <bool> Copy(File file, string destinationPath, string newname)
        {
            string destPath = destinationPath;

            newname = string.IsNullOrEmpty(newname) ? file.Name : newname;
            bool doRename = file.Name != newname;

            var link = await _linkManager.GetItemLink(file.FullPath, false);

            // копируем не саму ссылку, а её содержимое
            if (link != null)
            {
                var cloneRes = await CloneItem(destPath, link.Href.OriginalString);

                if (doRename || WebDavPath.Name(cloneRes.Path) != newname)
                {
                    string newFullPath = WebDavPath.Combine(destPath, WebDavPath.Name(cloneRes.Path));
                    var    renameRes   = await Rename(newFullPath, link.Name);

                    if (!renameRes)
                    {
                        return(false);
                    }
                }
                if (cloneRes.IsSuccess)
                {
                    _itemCache.Invalidate(destinationPath);
                }
                return(cloneRes.IsSuccess);
            }

            var qry = file.Files
                      .AsParallel()
                      .WithDegreeOfParallelism(Math.Min(MaxInnerParallelRequests, file.Files.Count))
                      .Select(async pfile =>
            {
                //var copyRes = await new CopyRequest(CloudApi, pfile.FullPath, destPath, ConflictResolver.Rewrite).MakeRequestAsync();
                var copyRes = await Account.RequestRepo.Copy(pfile.FullPath, destPath, ConflictResolver.Rewrite);
                if (!copyRes.IsSuccess)
                {
                    return(false);
                }

                if (doRename || WebDavPath.Name(copyRes.NewName) != newname)
                {
                    string newFullPath = WebDavPath.Combine(destPath, WebDavPath.Name(copyRes.NewName));
                    var renameRes      = await Rename(newFullPath, pfile.Name.Replace(file.Name, newname));
                    if (!renameRes)
                    {
                        return(false);
                    }
                }
                return(true);
            });

            _itemCache.Invalidate(destinationPath);
            bool res = (await Task.WhenAll(qry))
                       .All(r => r);

            return(res);
        }