Skip to content

Commit

Permalink
Merge branch 'safe_file_access'
Browse files Browse the repository at this point in the history
  • Loading branch information
DragonQ committed May 19, 2017
2 parents 183dc6f + 1695f83 commit e26d6c6
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 48 deletions.
80 changes: 78 additions & 2 deletions FileParser.vb
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,24 @@ Imports MusicFolderSyncer.Codec.CodecType
Imports MusicFolderSyncer.SyncSettings.TranscodeMode
Imports System.IO
Imports System.Environment
Imports System.Threading
#End Region

Class FileParser

Implements IDisposable

Private ProcessID As Int32
Private Shared FileTimeout As Int32 = 60
ReadOnly Property FilePath As String
Private FileLock As Boolean
Private MyGlobalSyncSettings As GlobalSyncSettings
Private SyncSettings As SyncSettings()
Private SourceFileStream As FileStream = Nothing

#Region " New "
Public Sub New(ByRef NewGlobalSyncSettings As GlobalSyncSettings, ByVal NewProcessID As Int32, ByVal NewFilePath As String, Optional NewSyncSettings As SyncSettings = Nothing)

ProcessID = NewProcessID
FilePath = NewFilePath
MyGlobalSyncSettings = NewGlobalSyncSettings
Expand All @@ -25,10 +32,72 @@ Class FileParser
Else
SyncSettings = {NewSyncSettings}
End If

SourceFileStream = WaitForFile(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read, FileTimeout)
If SourceFileStream Is Nothing Then
MyLog.Write(ProcessID, "Could not get file system lock on source file: """ & FilePath.Substring(MyGlobalSyncSettings.SourceDirectory.Length) & """.", Warning)
FileLock = False
Else
FileLock = True
End If

End Sub
#End Region

Public Overridable Sub Dispose() Implements IDisposable.Dispose
If Not SourceFileStream Is Nothing Then
SourceFileStream.Close()
End If
End Sub

#Region " Transfer File To Sync Folder "
Private Shared Function SafeCopy(SourceFileStream As FileStream, SyncFilePath As String) As ReturnObject

Dim MyReturnObject As ReturnObject

Try
If SourceFileStream Is Nothing Then Throw New Exception("Could not get file system lock on source file.")
Using NewFile As FileStream = WaitForFile(SyncFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.None, FileTimeout)
If Not NewFile Is Nothing Then
SourceFileStream.CopyTo(NewFile)
MyReturnObject = New ReturnObject(True, "", Nothing)
Else
MyReturnObject = New ReturnObject(False, "Could not get file system lock on destination file.", Nothing)
End If
End Using
Catch ex As Exception
MyReturnObject = New ReturnObject(False, ex.Message, 0)
End Try

Return MyReturnObject

End Function

Private Shared Function WaitForFile(fullPath As String, mode As FileMode, access As FileAccess, share As FileShare, timeoutSeconds As Int32) As FileStream
Dim msBetweenTries As Int32 = 500
Dim numTries As Int32 = CInt(Math.Ceiling(timeoutSeconds / (msBetweenTries / 1000)))

For count As Integer = 0 To numTries
Dim fs As FileStream = Nothing

Try
fs = New FileStream(fullPath, mode, access, share)

fs.ReadByte()
fs.Seek(0, SeekOrigin.Begin)

Return fs
Catch generatedExceptionName As IOException
If fs IsNot Nothing Then
fs.Dispose()
End If
Thread.Sleep(msBetweenTries)
End Try
Next

Return Nothing
End Function

Public Function TransferToSyncFolder() As ReturnObject

Dim MyReturnObject As ReturnObject
Expand All @@ -49,7 +118,8 @@ Class FileParser
SyncSetting.Encoder.GetFileExtensions(0)
Else
Directory.CreateDirectory(Path.GetDirectoryName(SyncFilePath))
File.Copy(FilePath, SyncFilePath, True)
Dim Result As ReturnObject = SafeCopy(SourceFileStream, SyncFilePath)
If Not Result.Success Then Throw New Exception(Result.ErrorMessage)
End If

Dim NewFile As New FileInfo(SyncFilePath)
Expand Down Expand Up @@ -144,7 +214,8 @@ Class FileParser
TranscodeFile(SyncFilePath, SyncSetting)
Else
Directory.CreateDirectory(Path.GetDirectoryName(SyncFilePath))
File.Copy(FilePath, SyncFilePath, True)
Dim Result As ReturnObject = SafeCopy(SourceFileStream, SyncFilePath)
If Not Result.Success Then Throw New Exception(Result.ErrorMessage)
End If

MyLog.Write(ProcessID, "...successfully added file to sync folder.", Information)
Expand Down Expand Up @@ -257,6 +328,11 @@ Class FileParser

Private Function CheckFileTags(MyCodec As Codec, SyncSetting As SyncSettings) As Boolean

If FileLock = False Then
MyLog.Write(ProcessID, "...could not obtain file tags. Could not get file system lock on source file.", Warning)
Return False
End If

Dim TagsObject As ReturnObject = MyCodec.MatchTag(FilePath, SyncSetting.GetWatcherTags)

If TagsObject.Success Then
Expand Down
6 changes: 3 additions & 3 deletions NewSyncWindow.xaml.vb
Original file line number Diff line number Diff line change
Expand Up @@ -580,9 +580,9 @@ Public Class NewSyncWindow
Dim TransferResult As ReturnObject

Try
Dim MyFileParser As New FileParser(MyGlobalSyncSettings, ProcessID, FilePath, SingleSyncSettings)
TransferResult = MyFileParser.TransferToSyncFolder()

Using MyFileParser As New FileParser(MyGlobalSyncSettings, ProcessID, FilePath, SingleSyncSettings)
TransferResult = MyFileParser.TransferToSyncFolder()
End Using
If TransferResult.Success Then
Dim NewSize As Int64 = CType(TransferResult.MyObject, Int64)

Expand Down
86 changes: 43 additions & 43 deletions TrayApp.vb
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,14 @@ Public Class TrayApp

If FilterMatch(e.Name) Then
MyLog.Write(FileID, "File renamed: " & e.FullPath, Information)
Dim MyFileParser As New FileParser(UserGlobalSyncSettings, FileID, e.FullPath)
Dim Result As ReturnObject = MyFileParser.RenameInSyncFolder(e.OldFullPath) 'RenameInSyncFolder(MyFileParser, e.OldFullPath)
If Result.Success Then
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File renamed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Info)
Else
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File rename failed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Error)
End If
MyFileParser = Nothing
Using MyFileParser As New FileParser(UserGlobalSyncSettings, FileID, e.FullPath)
Dim Result As ReturnObject = MyFileParser.RenameInSyncFolder(e.OldFullPath)
If Result.Success Then
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File renamed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Info)
Else
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File rename failed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Error)
End If
End Using
End If

If Interlocked.Equals(FileID, MaxFileID) Then
Expand All @@ -221,41 +221,41 @@ Public Class TrayApp
'Handles changed and new files

If FilterMatch(e.Name) Then
Dim MyFileParser As New FileParser(UserGlobalSyncSettings, FileID, e.FullPath)
Select Case e.ChangeType
Case Is = IO.WatcherChangeTypes.Changed
MyLog.Write(FileID, "Source file changed: " & e.FullPath, Information)
Dim Result As ReturnObject = MyFileParser.DeleteInSyncFolder()

If Result.Success Then
Result = MyFileParser.TransferToSyncFolder()
End If

If Result.Success Then
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File processed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Info)
Else
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File processing failed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Error)
End If
Case Is = IO.WatcherChangeTypes.Created
MyLog.Write(FileID, "Source file created: " & e.FullPath, Information)
Dim Result As ReturnObject = MyFileParser.TransferToSyncFolder()

If Result.Success Then
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File processed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Info)
Else
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File processing failed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Error)
End If
Case Is = IO.WatcherChangeTypes.Deleted
MyLog.Write(FileID, "Source file deleted: " & e.FullPath, Information)
Dim Result As ReturnObject = MyFileParser.DeleteInSyncFolder()

If Result.Success Then
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File deleted:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Info)
Else
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File deletion failed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Error)
End If
End Select
MyFileParser = Nothing
Using MyFileParser As New FileParser(UserGlobalSyncSettings, FileID, e.FullPath)
Select Case e.ChangeType
Case Is = IO.WatcherChangeTypes.Changed
MyLog.Write(FileID, "Source file changed: " & e.FullPath, Information)
Dim Result As ReturnObject = MyFileParser.DeleteInSyncFolder()

If Result.Success Then
Result = MyFileParser.TransferToSyncFolder()
End If

If Result.Success Then
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File processed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Info)
Else
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File processing failed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Error)
End If
Case Is = IO.WatcherChangeTypes.Created
MyLog.Write(FileID, "Source file created: " & e.FullPath, Information)
Dim Result As ReturnObject = MyFileParser.TransferToSyncFolder()

If Result.Success Then
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File processed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Info)
Else
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File processing failed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Error)
End If
Case Is = IO.WatcherChangeTypes.Deleted
MyLog.Write(FileID, "Source file deleted: " & e.FullPath, Information)
Dim Result As ReturnObject = MyFileParser.DeleteInSyncFolder()

If Result.Success Then
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File deleted:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Info)
Else
If Tray.Visible Then Tray.ShowBalloonTip(BalloonTime, "File deletion failed:", e.FullPath.Substring(UserGlobalSyncSettings.SourceDirectory.Length), ToolTipIcon.Error)
End If
End Select
End Using
End If

If Interlocked.Equals(FileID, MaxFileID) Then
Expand Down

0 comments on commit e26d6c6

Please sign in to comment.