My favorites | Sign in
Project Home Downloads Wiki Issues Source
Checkout   Browse   Changes    
 
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
#region usings

using SIO=System.IO;

#endregion

namespace BlogSharp.Core.Impl.Services.FileSystem
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Security.AccessControl;
using System.Transactions;
using Core.Services.FileSystem;
using Microsoft.Win32.SafeHandles;
using Native;
using SIO;

public class TransactionalFileService : IFileService
{
private readonly IProxyFactory factory;

public TransactionalFileService(IProxyFactory factory)
{
this.factory = factory;
}

#region IFileService Members

public virtual bool FileExists(string file)
{
using (var tranHandle = GetKtmTransactionHandle())
using (var handle = GetFileHandleForInfo(file, tranHandle))
return !handle.IsInvalid;
}

public virtual bool DirectoryExists(string directory)
{
return FileExists(directory);
}

public virtual void DeleteFile(IFile file)
{
DeleteFile(file.Path);
}

public virtual void DeleteFile(string file)
{
using (var tranHandle = GetKtmTransactionHandle())
NativeMethods.DeleteFileTransacted(file, tranHandle);
}

public virtual void MoveFile(string source, string destination)
{
using (var tranHandle = GetKtmTransactionHandle())
NativeMethods.MoveFileTransacted(source, destination, IntPtr.Zero, IntPtr.Zero,
NativeMethods.MoveFileFlags.MOVEFILE_REPLACE_EXISTING, tranHandle);
}

public virtual void MoveFile(IFile source, string destination)
{
using (var tranHandle = GetKtmTransactionHandle())
NativeMethods.MoveFileTransacted(source.Path, destination, IntPtr.Zero, IntPtr.Zero,
NativeMethods.MoveFileFlags.MOVEFILE_REPLACE_EXISTING, tranHandle);
}

public virtual void CopyFile(string source, string destination)
{
bool pbCancel = false;
using (var tranHandle = GetKtmTransactionHandle())
NativeMethods.CopyFileTransacted(source, destination, IntPtr.Zero, IntPtr.Zero, ref pbCancel,
NativeMethods.CopyFileFlags.COPY_FILE_FAIL_IF_EXISTS, tranHandle);
}

public virtual void CopyFile(IFile source, string destination)
{
CopyFile(source, destination);
}

public Stream OpenFileForRead(string source)
{
return OpenFile(source, FileMode.Open, FileAccess.Read, FileShare.None);
}

public Stream OpenFileForRead(IFile file)
{
return OpenFileForRead(file.Path);
}

public Stream OpenFileForWrite(string source)
{
return OpenFile(source, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
}

public Stream OpenFileForWrite(IFile file)
{
return OpenFileForWrite(file.Path);
}

public Stream OpenFile(string path, FileMode fileMode, FileAccess access, FileShare fileShare)
{
return OpenFileUnManaged(path, fileMode, access, fileShare);
}

public IFile GetFile(string file)
{
NativeMethods.WIN32_FIND_DATA findData;
using (var tranHandle = GetKtmTransactionHandle())
using (var fileHandle = GetFileHandleForInfo(file, tranHandle, out findData))
{
if (!fileHandle.IsInvalid)
return factory.CreateFileWithProxy(this, file, findData);
else
throw new FileNotFoundException();
}
}

public IDirectory GetDirectory(string directory)
{
NativeMethods.WIN32_FIND_DATA findData;
using (var tranHandle = GetKtmTransactionHandle())
using (var fileHandle = GetFileHandleForInfo(directory, tranHandle, out findData))
{
if (!fileHandle.IsInvalid)
return factory.CreateDirectoryWithProxy(this, directory);
else
throw new DirectoryNotFoundException();
}
}

public IFile CreateFile(string file, FileMode fileMode, FileAccess fileAccess, FileShare fileShare,
FileSystemRights fileSystemRights, FileOptions fileOptions, FileSecurity fileSecurity)
{
using (var tranHandle = GetKtmTransactionHandle())
{
int dwFlagsAndAttributes = (int) fileOptions;
dwFlagsAndAttributes |= 0x100000;
NativeMethods.FileAccess faccess = NativeFileEnums.TranslateFileAccess(fileAccess);
NativeMethods.FileShare fshare = NativeFileEnums.TranslateFileShare(fileShare);
NativeMethods.FileMode fmode = NativeFileEnums.TranslateFileMode(fileMode);
using (SafeFileHandle fileHandle = NativeMethods.CreateFileTransacted(file, faccess, fshare, IntPtr.Zero, fmode,
dwFlagsAndAttributes, IntPtr.Zero, tranHandle,
IntPtr.Zero, IntPtr.Zero))
{
if (fileHandle.IsInvalid)
throw new InvalidOperationException();
}
return GetFile(file);
}
}

public IFile CreateFile(string file, FileMode fileMode, FileAccess fileAccess, FileShare fileShare)
{
return CreateFile(file, fileMode, fileAccess, fileShare, 0, FileOptions.None, null);
}

public IFile CreateFile(string file, FileMode fileMode)
{
FileAccess access = GetFileAccessFromFileMode(fileMode);
return CreateFile(file, fileMode, access);
}

public IFile CreateFile(string file, FileMode fileMode, FileAccess fileAccess)
{
return CreateFile(file, fileMode, fileAccess, FileShare.Read);
}


public IFile CreateFile(string file)
{
return CreateFile(file, FileMode.CreateNew);
}

public IEnumerable<IFileSystemInfo> SearchDirectory(string directory, string searchPattern,
SearchOptions searchOptions, SearchLocation searchLocation)
{
using (var tranHandle = GetKtmTransactionHandle())
{
NativeMethods.WIN32_FIND_DATA win32findData;
var directoriesToBeSearched = new List<string>(8) {directory};

var output = new List<IFileSystemInfo>();
while (directoriesToBeSearched.Count > 0)
{
var count = directoriesToBeSearched.Count;
directory = directoriesToBeSearched[count - 1];
directoriesToBeSearched.RemoveAt(count - 1);

using (var directoryHandle = GetFileHandleForInfo(
directory + Path.DirectorySeparatorChar + @"*", tranHandle, out win32findData))
{
while (NativeMethods.FindNextFile(directoryHandle, out win32findData))
{
if (win32findData.cFileName.Equals("..") ||
win32findData.cFileName.Equals("."))
continue;
bool isFile = 0 == (win32findData.dwFileAttributes & 0x10);
string relative = directory + Path.DirectorySeparatorChar + win32findData.cFileName;
if (isFile & (searchOptions & SearchOptions.File) != 0)
output.Add(factory.CreateFileWithProxy(this, relative, win32findData));
else if (!isFile)
{
if (searchLocation == SearchLocation.Recursive)
directoriesToBeSearched.Add(relative);
if ((searchOptions & SearchOptions.Directory) != 0)
output.Add(factory.CreateDirectoryWithProxy(this, relative));
}
}
}
}
SortListByTypeAndName(output);
return new ReadOnlyCollection<IFileSystemInfo>(output);
}
}

#endregion

protected virtual bool IsInTransaction()
{
return Transaction.Current != null;
}

protected virtual KtmTransactionHandle GetKtmTransactionHandle()
{
return KtmTransactionHandle.CreateKtmTransactionHandle();
}

protected virtual Stream OpenFileUnManaged(string source, FileMode fileMode, FileAccess fileAccess,
FileShare fileShare)
{
using (var tranHandle = GetKtmTransactionHandle())
{
var fileHandle = GetFileHandle(source, tranHandle, fileMode, fileAccess, fileShare);
var stream = new FileStream(fileHandle, fileAccess);
if (fileMode == FileMode.Append)
stream.Position = stream.Length;
return stream;
}
}

protected virtual SafeFileHandle GetFileHandle(string source, KtmTransactionHandle tranHandle, FileMode fileMode,
FileAccess fileAccess, FileShare fileShare)
{
return NativeMethods.CreateFileTransacted(
source, NativeFileEnums.TranslateFileAccess(fileAccess),
NativeFileEnums.TranslateFileShare(fileShare), IntPtr.Zero,
NativeFileEnums.TranslateFileMode(fileMode), 0, IntPtr.Zero,
tranHandle, IntPtr.Zero, IntPtr.Zero);
}

protected virtual SafeFileHandle GetFileHandleForInfo(string source, KtmTransactionHandle tranHandle,
out NativeMethods.WIN32_FIND_DATA data)
{
var safeHandle = NativeMethods.FindFirstFileTransacted(source, NativeMethods.FINDEX_INFO_LEVELS.FindExInfoStandard,
out data,
NativeMethods.FINDEX_SEARCH_OPS.FindExSearchNameMatch,
IntPtr.Zero, 0, tranHandle);
return safeHandle;
}

protected virtual SafeFileHandle GetFileHandleForInfo(string source, KtmTransactionHandle tranHandle)
{
NativeMethods.WIN32_FIND_DATA data;
return GetFileHandleForInfo(source, tranHandle, out data);
}

protected virtual FileAccess GetFileAccessFromFileMode(FileMode fileMode)
{
return fileMode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite;
//switch (fileMode)
//{
// case FileMode.Append:
// return FileAccess.Write;
// case FileMode.CreateNew:
// case FileMode.Create:
// case FileMode.Open:
// case FileMode.OpenOrCreate:
// case FileMode.Truncate:
// default:
// return FileAccess.ReadWrite;
//}
}

protected virtual void SortListByTypeAndName(List<IFileSystemInfo> output)
{
output.Sort(delegate(IFileSystemInfo info1, IFileSystemInfo info2)
{
if (info1.Type == FileSystemType.Directory && info2.Type == FileSystemType.File)
return 1;
else if (info1.Type == FileSystemType.File && info2.Type == FileSystemType.Directory)
return -1;
else
return info1.Path.CompareTo(info2.Path);
});
}
}
}

Change log

r108 by tehlike on Jul 17, 2009   Diff
Huge code clean (via resharper)
Go to: 
Project members, sign in to write a code review

Older revisions

r88 by tehlike on Feb 23, 2009   Diff
Marking a test as ignored for further
investigation
r87 by tehlike on Feb 22, 2009   Diff
More cleanup & stylecop goodies.
r86 by tehlike on Feb 22, 2009   Diff
Some cleanup + StyleCop goodies. More
to come.
All revisions of this file

File info

Size: 10420 bytes, 297 lines
Powered by Google Project Hosting