Пример #1
0
        /// <summary>
        /// このファイルセットの変更点を全てファイルに保存します.
        /// </summary>
        /// <returns></returns>
        /// <exception cref="IOException"></exception>
        public async Task FlushAsync()
        {
            //上書きされたファイルや削除フラグが立ったファイルsが存在しなければ何もしないで終了
            if (!this.files.Any(file => file.OverWritten || file.RequaredRemove))
            {
                return;
            }
            //削除フラグが立ったファイルをリストから削除
            this.files.RemoveAll(file => file.RequaredRemove);
            //まだ読み込まれていないファイルを読み込む.同時に複数のファイルが読み込まれるのを防ぐためにWait()する
            foreach (var file in this.files)
            {
                if (file.Data == null)
                {
                    await this.ReadAsync(file.Name);
                }
            }
            //キーを更新
            this.originalKey = new byte[this.Key.Length];
            this.Key.CopyTo(this.originalKey, 0);
            //
            this.stream?.Dispose();
            //書き込みモードでファイルを開き直す
            this.stream = await(await ApplicationStorage.GetOrCreateFileAsync(this.targetFoldernames, this.targetFilename)).OpenStreamForWriteAsync();
            this.stream.SetLength(0);
            //ファイル数を書き込む
            await this.WriteInt32Async(this.files.Count);

            //各ファイルの内容を書き込む
            foreach (var file in files)
            {
                //ファイル名サイズ
                await this.WriteInt32Async(file.NameSize);

                //ファイルサイズ
                await this.WriteInt32Async(file.Size);

                //ファイル名
                await this.WriteBytesAsync(Encoding.Unicode.GetBytes(file.Name));

                //ファイルの中身
                await this.WriteBytesAsync(file.Data);
            }
            //保存
            await this.stream.FlushAsync();

            this.stream.Dispose();
            //読み込みモードでファイルを開き直す
            this.stream = await(await ApplicationStorage.GetOrCreateFileAsync(this.targetFoldernames, this.targetFilename)).OpenStreamForReadAsync();
            //読み込んだファイルの中身と,上書き保存フラグをリセット(メモリ使用量を減らす)
            foreach (var file in files)
            {
                file.OverWritten  = false;
                file.OriginalSize = file.Size;
                file.Data         = null;
            }
        }
Пример #2
0
        /// <summary>
        /// 指定したパスの暗号化ファイルセットを開きます.
        /// </summary>
        /// <param name="foldernames">暗号化ファイルセットが存在するフォルダ.</param>
        /// <param name="filename">暗号化ファイルセットの名前.</param>
        /// <param name="key">暗号化ファイルセットに適用するキー.</param>
        /// <param name="createOption">trueに設定した場合,ファイルやフォルダが存在しない場合は新規作成されます.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="FileNotFoundException"></exception>
        /// <exception cref="IOException"></exception>
        public static async Task <CryptoFileset> OpenOrCreateCryptoFilesetAsync(IEnumerable <string> foldernames, string filename, byte[] key, bool createOption)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (key.Length == 0)
            {
                throw new ArgumentException($"{nameof(key)} must have a element at least.");
            }
            var alreadyExisted = await ApplicationStorage.Exists(foldernames, filename);

            if (!alreadyExisted)
            {
                if (createOption)
                {
                    await ApplicationStorage.GetOrCreateFileAsync(foldernames, filename);
                }
                else
                {
                    throw new FileNotFoundException("The specified file does not exist.");
                }
            }
            var storage = await ApplicationStorage.GetOrCreateFileAsync(foldernames, filename);

            CryptoFileset cryptoFileset = new CryptoFileset()
            {
                targetFoldernames = foldernames,
                targetFilename    = filename,
                Key         = new byte[key.Length],
                originalKey = new byte[key.Length],
            };

            if (alreadyExisted)
            {
                try
                {
                    cryptoFileset.stream = await storage.OpenStreamForReadAsync();

                    //中身が空ならまだセーブしてない状態なので,読み込まずに終了
                    if (cryptoFileset.stream.Length == 0)
                    {
                        return(cryptoFileset);
                    }
                    //
                    var fileCount = cryptoFileset.ReadInt32();
                    while (cryptoFileset.files.Count < fileCount)
                    {
                        CodedFile file = new CodedFile()
                        {
                            //ファイル名のサイズを読み込む
                            NameSize = cryptoFileset.ReadInt32(),
                            //ファイルサイズを読み込む
                            OriginalSize = cryptoFileset.ReadInt32()
                        };
                        file.Size = file.OriginalSize;
                        //ファイル名を取得
                        file.Name = Encoding.Unicode.GetString(cryptoFileset.ReadBytes(file.NameSize), 0, file.NameSize);
                        //ファイルの中身は読み飛ばす。シークして次のファイルデータの先頭位置へ
                        cryptoFileset.stream.Seek(file.OriginalSize, SeekOrigin.Current);
                        //読み込んだ内容を追加
                        cryptoFileset.files.Add(file);
                    }
                }
                catch
                {
                    throw new IOException("Cannot read the file.");
                }
            }
            return(cryptoFileset);
        }