/
Chunker.cs
139 lines (102 loc) · 5.01 KB
/
Chunker.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Rainbows, an experimental backend for SparkleShare
// Copyright (C) 2011 Hylke Bons <hylkebons@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.IO;
namespace Rainbows {
// Also turns chunk objects into a file.
//
public class Chunker {
public string OutputDirectory;
public delegate void ChunkCreatedHandler (string chunk_file_path, int chunk_size, string chunk_hash);
public event ChunkCreatedHandler ChunkCreated;
public Crypto ChunkCrypto;
public delegate string NameChunkDelegate (string chunk_file_name);
public NameChunkDelegate NameChunk = delegate (string chunk_file_name) {
return null;
};
public Chunker (string output_directory)
{
OutputDirectory = output_directory;
if (!Directory.Exists (OutputDirectory))
Directory.CreateDirectory (OutputDirectory);
}
// Turns files into chunk objects and stores them in the database.
public string FileToChunks (string source_file_path, int chunk_size)
{
List <string> chunk_paths = new List<string> ();
using (FileStream stream = File.OpenRead (source_file_path))
{
stream.Lock (0, stream.Length);
List<string> new_chunk_paths = new List<string> ();
try {
int current_chunk_size = 0;
byte[] buffer = new byte [chunk_size];
int chunk_number = 1;
while ((current_chunk_size = stream.Read (buffer, 0, buffer.Length)) > 0)
{
string hash = Utils.SHA1 (buffer);
string chunk_file_path = NameChunk (hash);
if (chunk_file_path == null)
chunk_file_path = Path.Combine (OutputDirectory, hash);
string chunk_container_path = Path.GetDirectoryName (chunk_file_path);
// TODO: Calculate SHA1 hash of the full file here too
if (!File.Exists (chunk_file_path)) {
if (!Directory.Exists (chunk_container_path))
Directory.CreateDirectory (chunk_container_path);
if (ChunkCrypto != null) {
byte [] crypto_buffer = ChunkCrypto.Encrypt (buffer);
File.WriteAllBytes (chunk_file_path, crypto_buffer);
} else {
File.WriteAllBytes (chunk_file_path, buffer);
new_chunk_paths.Add (chunk_file_path);
}
chunk_paths.Add (chunk_file_path);
if (ChunkCreated != null) // TODO: return full file hash too
ChunkCreated (chunk_file_path, current_chunk_size, hash);
Console.WriteLine ("Chunk " + hash + " created");
} else {
Console.WriteLine ("Chunk " + hash + " exists");
}
chunk_number++;
}
} catch (IOException) {
foreach (string new_chunk_path in new_chunk_paths) {
if (File.Exists (new_chunk_path))
File.Delete (new_chunk_path); // TODO: what to do with ongoing transfers?
}
} finally {
stream.Unlock (0, stream.Length);
}
return ""; // Full hash
}
}
public void ChunksToFile (string [] chunk_file_paths, string target_file_path)
{
using (FileStream stream = File.OpenWrite (target_file_path))
{
Console.WriteLine ("Creating file from chunks...");
byte [] buffer;
foreach (string chunk_path in chunk_file_paths) {
buffer = File.ReadAllBytes (chunk_path);
if (ChunkCrypto != null)
buffer = ChunkCrypto.Decrypt (buffer);
stream.Write (buffer, 0, buffer.Length);
}
}
}
}
}