File: FileSystemOperation.vb

package info (click to toggle)
mono-basic 2.6.2-2
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 18,852 kB
  • ctags: 809
  • sloc: cs: 8,852; makefile: 516; sh: 307
file content (554 lines) | stat: -rw-r--r-- 21,440 bytes parent folder | download
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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
'
' FileSystemOperation.vb
'
' Authors:
'   Rolf Bjarne Kvinge (RKvinge@novell.com>
'
' Copyright (C) 2007 Novell (http://www.novell.com)
'
' Permission is hereby granted, free of charge, to any person obtaining
' a copy of this software and associated documentation files (the
' "Software"), to deal in the Software without restriction, including
' without limitation the rights to use, copy, modify, merge, publish,
' distribute, sublicense, and/or sell copies of the Software, and to
' permit persons to whom the Software is furnished to do so, subject to
' the following conditions:
' 
' The above copyright notice and this permission notice shall be
' included in all copies or substantial portions of the Software.
' 
' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
' EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
' MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
' NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
' LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
' OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
' WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
'

#If NET_VER >= 2.0 Then
Imports System.IO
Imports System.Text
Imports System.Collections.ObjectModel
Imports System.Collections.Generic

Namespace Microsoft.VisualBasic.FileIO
    Friend Class FileSystemOperation
        Private m_Source As String
        Private m_Destination As String
        Private m_Overwrite As Boolean
        Private m_DirectoryNotEmpty As DeleteDirectoryOption
        Private m_ShowUI As Boolean
        Private m_ShowUIOption As UIOption
        Private m_UICancelOption As UICancelOption
        Private m_Recycle As RecycleOption
#If TARGET_JVM = False Then 'Windows.Forms Not Supported by Grasshopper
        Private m_UI As FileSystemOperationUI
#End If
        Private m_Sources As New Generic.List(Of Info)
        Private m_TotalSize As Long
        Private m_Cancelled As Boolean
        Private m_Errors As New Generic.Dictionary(Of String, String)

        Private Class Info
            Public Name As String
            Public Size As Long
            Public IsDir As Boolean
        End Class

#Region "Constructors"
        Sub New(ByVal Source As String, ByVal Destination As String, ByVal ShowUIOption As UIOption, ByVal UICancelOption As UICancelOption, ByVal ShowUI As Boolean, ByVal overwrite As Boolean)
            Me.m_Source = Source
            Me.m_Destination = Destination
            Me.m_ShowUI = ShowUI
            Me.m_ShowUIOption = ShowUIOption
            Me.m_UICancelOption = UICancelOption
            Me.m_Overwrite = overwrite
        End Sub

        Sub New(ByVal Source As String, ByVal Destination As String, ByVal ShowUIOption As UIOption, ByVal UICancelOption As UICancelOption)
            Me.m_Source = Source
            Me.m_Destination = Destination
            Me.m_ShowUI = True
            Me.m_ShowUIOption = ShowUIOption
            Me.m_UICancelOption = UICancelOption
            Me.m_Overwrite = False
        End Sub

        Sub New(ByVal Source As String, ByVal Destination As String, ByVal Overwrite As Boolean)
            Me.m_Source = Source
            Me.m_Destination = Destination
            Me.m_ShowUI = False
            Me.m_Overwrite = Overwrite
        End Sub

        Sub New(ByVal Directory As String, ByVal ShowUIOption As UIOption, ByVal Recycle As RecycleOption, ByVal UICancelOption As UICancelOption, ByVal onDirectoryNotEmpty As DeleteDirectoryOption, ByVal ShowUI As Boolean)
            Me.m_Source = Directory
            Me.m_ShowUI = ShowUI
            Me.m_ShowUIOption = ShowUIOption
            Me.m_UICancelOption = UICancelOption
            Me.m_Recycle = Recycle
            Me.m_DirectoryNotEmpty = onDirectoryNotEmpty
            Me.m_Overwrite = False
        End Sub

        Sub New(ByVal Directory As String, ByVal ShowUIOption As UIOption, ByVal Recycle As RecycleOption, ByVal UICancelOption As UICancelOption, ByVal ShowUI As Boolean)
            Me.m_Source = Directory
            Me.m_ShowUI = ShowUI
            Me.m_ShowUIOption = ShowUIOption
            Me.m_UICancelOption = UICancelOption
            Me.m_Recycle = Recycle
            Me.m_Overwrite = False
        End Sub
#End Region
#Region "Public Methods"
        Sub Cancel()
            m_Cancelled = True
        End Sub

        Sub ExecuteFileCopy()
            Try
                Init("Copy")
                LoadSources(False, True)
                Copy()
            Finally
                CleanUp()
            End Try
        End Sub

        Sub ExecuteFileMove()
            Try
                Init("Move")
                LoadSources(False, True)
                Move()
            Finally
                CleanUp()
            End Try
        End Sub

        Sub ExecuteDirCopy()
            Try
                Init("Copy")
                LoadSources(True, True)
                Copy()
            Finally
                CleanUp()
            End Try
        End Sub

        Sub ExecuteDirMove()
            Try
                Init("Move")

                If IO.Directory.Exists(m_Source) = False Then
                    Throw New IOException(String.Format("Could not find directory '{0}'.", m_Source))
                End If

                LoadSources(True, False)
                Move()
            Finally
                CleanUp()
            End Try
        End Sub

        Sub ExecuteDirDelete()
            Try
                Init("Delete")
                If IO.Directory.Exists(m_Source) = False Then
                    Return
                End If

                LoadSources(m_Source, m_DirectoryNotEmpty = DeleteDirectoryOption.DeleteAllContents, False)
                If m_DirectoryNotEmpty = DeleteDirectoryOption.ThrowIfDirectoryNonEmpty AndAlso m_Sources.Count > 1 Then
                    Throw New IOException("Directory not empty")
                End If
                Delete()
            Finally
                CleanUp()
            End Try
        End Sub

        Sub ExecuteFileDelete()
            Try
                Init("Delete")
                LoadSources(m_Source, False, False)
                Delete()
            Finally
                CleanUp()
            End Try
        End Sub
#End Region

        Private Function GetDestination(ByVal Source As String) As String
            Dim result As String

            result = Source.Replace(m_Source, m_Destination)

            Return result
        End Function

        Private Sub Move()
            Dim counter As Integer
            Dim size As Long

            size = 0

            If OnSameVolume Then
                If IsDirectory(m_Source) Then
                    UpdateUI(Path.GetDirectoryName(m_Source), m_Destination, Path.GetFileName(m_Source), 0, 0)
                    System.IO.Directory.Move(m_Source, m_Destination)
                Else
                    If IO.File.Exists(m_Destination) Then
                        If DoOverwrite(m_Source, m_Destination) Then
                            System.IO.File.Delete(m_Destination)
                        Else
                            m_Cancelled = True
                            Return
                        End If
                    End If
                    System.IO.File.Move(m_Source, m_Destination)
                End If
            Else
                For i As Integer = m_Sources.Count - 1 To 0 Step -1
                    Dim info As Info = m_Sources(i)
                    Dim item As String = info.Name
                    Dim destination As String

                    destination = GetDestination(item)

                    CopyItem(info, destination, counter, size)
                    If m_Cancelled Then Return
                    DeleteItem(info, counter, False)
                    counter += 1


                    If m_Cancelled Then Return
                Next
            End If

            UpdateUI(Nothing, Nothing, Nothing, m_Sources.Count, 0)
        End Sub

        Private Sub Copy()
            Dim counter As Integer
            Dim size As Long

            size = 0
            For i As Integer = 0 To m_Sources.Count - 1
                Dim info As Info = m_Sources(i)
                Dim item As String = info.Name
                Dim destination As String

                destination = GetDestination(item)

                CopyItem(info, destination, counter, size)
                counter += 1

                If m_Cancelled Then Return
            Next
            UpdateUI(Nothing, Nothing, Nothing, m_Sources.Count, size)
        End Sub

        Private Sub CopyItem(ByVal Info As Info, ByVal Destination As String, ByVal Counter As Integer, ByRef Size As Long)
            Dim Source As String = Info.Name
            If Info.IsDir Then
                UpdateUI(Source, Nothing, Nothing, Counter, 0)
                If IO.Directory.Exists(Destination) = False Then
                    IO.Directory.CreateDirectory(Destination)
                End If
            Else
                UpdateUI(Path.GetDirectoryName(Source), Path.GetDirectoryName(Destination), Path.GetFileName(Source), Counter, Size)
                CopyFile(Source, Destination, Size)
            End If
        End Sub

        Private Sub DeleteItem(ByVal Info As Info, ByVal Counter As Integer, ByVal DoUpdate As Boolean)
            Dim Item As String = Info.Name
            If Info.IsDir Then
                If DoUpdate Then UpdateUI(Item, Nothing, Nothing, Counter, 0)
                System.IO.Directory.Delete(Item, False)
            Else
                If DoUpdate Then UpdateUI(Path.GetDirectoryName(Item), Nothing, Path.GetFileName(Item), Counter, 0)
                System.IO.File.Delete(Item)
            End If
        End Sub

        Private Function IsDirectory(ByVal Path As String) As Boolean
            Return CBool(System.IO.File.GetAttributes(Path) And FileAttributes.Directory)
        End Function

        Private Sub CopyFile(ByVal Source As String, ByVal Destination As String, ByRef Size As Long)
            Dim newFileMode As FileMode

            If IO.File.Exists(Destination) Then
                If DoOverwrite(Source, Destination) = False Then Return
                newFileMode = FileMode.Create
            Else
                newFileMode = FileMode.CreateNew
            End If

            Try
#If TARGET_JVM = False Then 'FileStream ctor with FileOptions Not Supported by Grasshopper
                Using reader As New IO.FileStream(Source, FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.SequentialScan)
                    Using writer As New IO.FileStream(Destination, newFileMode, FileAccess.Write, FileShare.Read, 1024, FileOptions.SequentialScan)
#Else
                Using reader As New IO.FileStream(Source, FileMode.Open, FileAccess.Read, FileShare.Read, 1024)
                    Using writer As New IO.FileStream(Destination, newFileMode, FileAccess.Write, FileShare.Read)
#End If
                        Dim read As Integer
                        Dim buffer(1023) As Byte

                        Do
                            read = reader.Read(buffer, 0, 1024)
                            writer.Write(buffer, 0, read)
                            Size = Size + CLng(read)
                            UpdateUI(Size)
                        Loop Until read = 0 OrElse m_Cancelled
                    End Using
                End Using
            Catch ex As IOException
                m_Errors.Add(Source, ex.Message)
            End Try
        End Sub

        Private Sub Delete()
            Dim counter As Integer

            If m_Recycle = RecycleOption.SendToRecycleBin Then
                Throw New NotImplementedException
            Else
                For i As Integer = m_Sources.Count - 1 To 0 Step -1
                    Dim info As Info = m_Sources(i)
                    Dim item As String = info.Name

                    DeleteItem(info, counter, True)
                    counter += 1

                    If m_Cancelled Then Return
                Next
            End If

            UpdateUI(Nothing, Nothing, Nothing, m_Sources.Count, 0)
        End Sub

        Private Sub Recycle(ByVal Source As String)

        End Sub

        Private Sub LoadSources(ByVal Recursive As Boolean, ByVal SizeMatters As Boolean)
            m_TotalSize = 0

            LoadSources(m_Source, Recursive, SizeMatters, 0)

        End Sub

        Private Sub LoadSources(ByVal Source As String, ByVal Recursive As Boolean, ByVal SizeMatters As Boolean, Optional ByRef DirSize As Long = 0)
            Dim subdirs() As String
            Dim files() As String

            Dim info2 As Info = Nothing
            Dim subsize As Long
            If CBool(System.IO.File.GetAttributes(Source) And FileAttributes.Directory) Then
                info2 = New Info
                info2.Name = Source
                info2.IsDir = True
                m_Sources.Add(info2)
                Debug.WriteLine(info2.Name)


                files = System.IO.Directory.GetFiles(Source)
                For Each file As String In files
                    Dim info As New Info
                    info.Name = file
                    info.IsDir = False
                    If SizeMatters Then
                        info.Size = (New FileInfo(file)).Length
                        m_TotalSize += info.Size
                        DirSize += info.Size
                    End If
                    m_Sources.Add(info)
                    Debug.WriteLine(info.Name)
                Next

                If Recursive Then
                    subdirs = System.IO.Directory.GetDirectories(Source)
                    For Each subdir As String In subdirs
                        LoadSources(subdir, Recursive, SizeMatters, subsize)
                    Next
                End If

                If info2 IsNot Nothing Then
                    info2.Size = subsize
                    DirSize += subsize
                End If
            Else
                Dim info As New Info
                info.Name = Source
                m_Sources.Add(info)
                If SizeMatters Then
                    info.Size = (New FileInfo(Source)).Length
                    m_TotalSize = info.Size
                End If
            End If

        End Sub

        Private Sub Init(ByVal Title As String)
            m_Source = Path.GetFullPath(m_Source)
            If m_Destination <> String.Empty Then
                m_Destination = Path.GetFullPath(m_Destination)
            End If

            If m_ShowUI = False Then Return
#If TARGET_JVM = False Then 'Windows.Forms Not Supported by Grasshopper
            m_UI = New FileSystemOperationUI(Me)
            m_UI.Text = Title
            m_UI.lblDirs.Text = "Calculating time..."
            m_UI.lblFile.Text = String.Empty
            m_UI.lblTimeLeft.Text = "..."
            m_UI.barProgress.Value = 0
            m_UI.Show()
#End If
        End Sub

        Private Sub UpdateUI(ByVal SizeDone As Long)
            If m_ShowUI = False Then Return

            Dim PercentDone As Double
            If SizeDone > 0 AndAlso m_TotalSize > 0 Then
                PercentDone = SizeDone / m_TotalSize * 100
            Else
                PercentDone = 0
            End If
#If TARGET_JVM = False Then 'Windows.Forms Not Supported by Grasshopper
            m_UI.UpdateInfo(PercentDone)
#End If
        End Sub

        Private Sub UpdateUI(ByVal SourceDirectory As String, ByVal DestinationDirectory As String, ByVal File As String, ByVal ItemsDone As Integer, ByVal SizeDone As Long)
            If m_ShowUI = False Then Return

            Dim PercentDone As Double
            If SizeDone > 0 AndAlso m_TotalSize > 0 Then
                PercentDone = SizeDone / m_TotalSize * 100
            ElseIf ItemsDone > 0 AndAlso m_Sources.Count > 0 Then
                PercentDone = ItemsDone / m_Sources.Count
            Else
                PercentDone = 0
            End If
#If TARGET_JVM = False Then 'Windows.Forms Not Supported by Grasshopper
            m_UI.UpdateInfo(SourceDirectory, DestinationDirectory, File, PercentDone)
#End If
        End Sub

        Private Sub CleanUp()
            If m_ShowUI Then
#If TARGET_JVM = False Then 'Windows.Forms Not Supported by Grasshopper
                If m_UI IsNot Nothing Then m_UI.Dispose()
                m_UI = Nothing
#End If

                If m_Cancelled AndAlso m_UICancelOption = UICancelOption.ThrowException Then
                    Throw New OperationCanceledException("The operation was canceled.")
                End If
            End If

            If m_Errors.Count > 0 Then
                If CBool(File.GetAttributes(m_Source) And FileAttributes.Directory) = False Then
                    Throw New IOException(m_Errors(m_Source))
                Else
                    Dim ex As New IOException("Could not complete operation on some files and directories. See the Data property of the exception for more details.")
                    For Each entry As KeyValuePair(Of String, String) In m_Errors
                        ex.Data.Add(entry.Key, entry.Value)
                    Next
                    Throw ex
                End If
            End If
        End Sub

        Private Sub CopyDir(ByVal SourceDir As String, ByVal DestinationDir As String)
            If IO.Directory.Exists(DestinationDir) = False Then
                IO.Directory.CreateDirectory(DestinationDir)
            End If

            Dim files() As String = IO.Directory.GetFiles(SourceDir)
            Dim subdirs() As String = IO.Directory.GetDirectories(SourceDir)

            For Each file As String In files
                System.IO.File.Copy(file, Path.Combine(DestinationDir, Path.GetFileName(file)))
            Next

            For Each subdir As String In subdirs
                Dim name As String = Path.GetFileName(subdir)
                CopyDir(Path.Combine(SourceDir, name), Path.Combine(DestinationDir, name))
            Next
        End Sub

        Private Function DoOverwrite(ByVal Source As String, ByVal Destination As String) As Boolean
            If m_ShowUI Then
                Static overWriteAll As Boolean
                Static overWriteNone As Boolean

                If overWriteAll Then Return True
                If overWriteNone Then Return False

                If m_ShowUIOption = UIOption.OnlyErrorDialogs Then Return True
#If TARGET_JVM = False Then 'Windows.Forms Not Supported by Grasshopper
                Using frm As New FileSystemOperationUIQuestion
                    Dim result As FileSystemOperationUIQuestion.Answer
                    Dim infoA As FileInfo = New FileInfo(Source)
                    Dim infoB As FileInfo = New FileInfo(Destination)

                    frm.Text = "Confirm file overwrite"
                    frm.lblTitle.Text = String.Format("This folder already has a file called '{0}'.", Path.GetFileName(Source))
                    frm.lblText1.Text = "Do you want to replace the existing file"
                    frm.lblText2.Text = "with this other file?"
                    frm.lblSizeA.Text = String.Format("{0} bytes", infoA.Length)
                    frm.lblSizeB.Text = String.Format("{0} bytes", infoB.Length)
                    frm.lblDateA.Text = String.Format("modified: {0}", infoA.LastWriteTime)
                    frm.lblDateB.Text = String.Format("modified: {0}", infoB.LastWriteTime)
                    frm.iconA.Image = System.Drawing.Icon.ExtractAssociatedIcon(Source).ToBitmap
                    frm.iconB.Image = System.Drawing.Icon.ExtractAssociatedIcon(Destination).ToBitmap

                    result = frm.ShowDialog()

                    Select Case result
                        Case FileSystemOperationUIQuestion.Answer.Cancel
                            m_Cancelled = True
                            Return False
                        Case FileSystemOperationUIQuestion.Answer.No
                            Return False
                        Case FileSystemOperationUIQuestion.Answer.NoToAll
                            overWriteNone = True
                            Return False
                        Case FileSystemOperationUIQuestion.Answer.Yes
                            Return True
                        Case FileSystemOperationUIQuestion.Answer.YesToAll
                            overWriteAll = True
                            Return True
                        Case Else
                            Return False
                    End Select
                End Using
#End If
            Else
                If m_Overwrite = False Then
                    m_Errors.Add(Source, String.Format("The file '{0}' already exists.", Destination))
                End If
                Return m_Overwrite
            End If
        End Function

        Private ReadOnly Property OnSameVolume() As Boolean
            Get
                Return IsOnSameVolume(m_Source, m_Destination)
            End Get
        End Property

        Private Shared Function IsOnSameVolume(ByVal Source As String, ByVal Destination As String) As Boolean
            Return Char.ToUpperInvariant(Source(0)) = Char.ToUpperInvariant(Destination(0))
        End Function
    End Class

End Namespace
#End If