Filesystem: Cut path in half if too long

This commit is contained in:
Jonathan Jenne 2021-04-14 11:08:30 +02:00
parent ddd04a6f8a
commit db8e80dd50

View File

@ -23,8 +23,8 @@ Imports DigitalData.Modules.Logging
''' <remarks> ''' <remarks>
''' </remarks> ''' </remarks>
Public Class File Public Class File
Private ReadOnly _logger As Logger Private ReadOnly _Logger As Logger
Private ReadOnly _logConfig As LogConfig Private ReadOnly _LogConfig As LogConfig
Private ReadOnly _invalidFilenameChars As String Private ReadOnly _invalidFilenameChars As String
Private ReadOnly _invalidPathChars As String Private ReadOnly _invalidPathChars As String
@ -32,36 +32,42 @@ Public Class File
Private Const REGEX_CLEAN_FILENAME As String = "[\\/:""<>|\b\0\r\n\t]" Private Const REGEX_CLEAN_FILENAME As String = "[\\/:""<>|\b\0\r\n\t]"
Private Const REGEX_CLEAN_PATH As String = "[:""<>|\b\0\r\n\t]" Private Const REGEX_CLEAN_PATH As String = "[:""<>|\b\0\r\n\t]"
' The limit enforced by windows for filenpaths is 260,
' so we use a slightly smaller number to have some Error margin.
'
' Source: https://docs.microsoft.com/de-de/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#maximum-path-length-limitation
Private Const MAX_FILE_PATH_LENGTH = 250
Private Const FILE_NAME_ACCESS_TEST = "accessTest.txt" Private Const FILE_NAME_ACCESS_TEST = "accessTest.txt"
Public Sub New(LogConfig As LogConfig) Public Sub New(LogConfig As LogConfig)
_logConfig = LogConfig _LogConfig = LogConfig
_logger = LogConfig.GetLogger() _Logger = LogConfig.GetLogger()
_invalidFilenameChars = String.Join("", Path.GetInvalidFileNameChars()) _invalidFilenameChars = String.Join("", Path.GetInvalidFileNameChars())
_invalidPathChars = String.Join("", Path.GetInvalidPathChars()) _invalidPathChars = String.Join("", Path.GetInvalidPathChars())
End Sub End Sub
Public Function GetCleanFilename(FileName As String) As String Public Function GetCleanFilename(FileName As String) As String
_logger.Debug("Filename before cleaning: [{0}]", FileName) _Logger.Debug("Filename before cleaning: [{0}]", FileName)
Dim oCleanName As String = FileName Dim oCleanName As String = FileName
oCleanName = Regex.Replace(oCleanName, _invalidFilenameChars, String.Empty) oCleanName = Regex.Replace(oCleanName, _invalidFilenameChars, String.Empty)
oCleanName = Regex.Replace(oCleanName, REGEX_CLEAN_FILENAME, String.Empty, RegexOptions.Singleline) oCleanName = Regex.Replace(oCleanName, REGEX_CLEAN_FILENAME, String.Empty, RegexOptions.Singleline)
_logger.Debug("Filename after cleaning: [{0}]", oCleanName) _Logger.Debug("Filename after cleaning: [{0}]", oCleanName)
Return oCleanName Return oCleanName
End Function End Function
Public Function GetCleanPath(FilePath As String) As String Public Function GetCleanPath(FilePath As String) As String
_logger.Debug("Path before cleaning: [{0}]", FilePath) _Logger.Debug("Path before cleaning: [{0}]", FilePath)
Dim oCleanName As String = FilePath Dim oCleanName As String = FilePath
oCleanName = Regex.Replace(oCleanName, _invalidPathChars, String.Empty) oCleanName = Regex.Replace(oCleanName, _invalidPathChars, String.Empty)
oCleanName = Regex.Replace(oCleanName, REGEX_CLEAN_PATH, String.Empty, RegexOptions.Singleline) oCleanName = Regex.Replace(oCleanName, REGEX_CLEAN_PATH, String.Empty, RegexOptions.Singleline)
_logger.Debug("Path after cleaning: [{0}]", oCleanName) _Logger.Debug("Path after cleaning: [{0}]", oCleanName)
Return oCleanName Return oCleanName
End Function End Function
@ -118,20 +124,32 @@ Public Class File
oFileVersion = 1 oFileVersion = 1
End If End If
' Shorten the filename (only filename, without extension or version)
' by cutting the length in half. This should work no matter how long the path and/or filename are.
If oFileName.Length > MAX_FILE_PATH_LENGTH Then
_Logger.Info("Filename is too long. Filename will be cut to prevent further errors.")
_Logger.Info("Original Filename is: {0}", oFileNameWithoutExtension)
Dim oNewLength As Integer = Math.Round(oFileNameWithoutExtension.Length / 2)
Dim oNewFileNameWithoutExtension = oFileNameWithoutExtension.Substring(0, oNewLength)
_Logger.Info("New Filename will be: {0}", oNewFileNameWithoutExtension)
oFileNameWithoutExtension = oNewFileNameWithoutExtension
End If
' while file exists, increment version ' while file exists, increment version
Do Do
oFinalFileName = Path.Combine(oDestinationDir, GetFilenameWithVersion(oFileNameWithoutExtension, oVersionSeparator, oFileVersion, oExtension)) oFinalFileName = Path.Combine(oDestinationDir, GetFilenameWithVersion(oFileNameWithoutExtension, oVersionSeparator, oFileVersion, oExtension))
_logger.Debug("Intermediate Filename is {0}", oFinalFileName) _Logger.Debug("Intermediate Filename is {0}", oFinalFileName)
_logger.Debug("File version: {0}", oFileVersion) _Logger.Debug("File version: {0}", oFileVersion)
oFileVersion += 1 oFileVersion += 1
Loop While (IO.File.Exists(oFinalFileName)) Loop While (IO.File.Exists(oFinalFileName))
_logger.Debug("Final Filename is {0}", oFinalFileName) _Logger.Debug("Final Filename is {0}", oFinalFileName)
Return oFinalFileName Return oFinalFileName
Catch ex As Exception Catch ex As Exception
_logger.Warn("Filename {0} could not be versioned. Original filename will be returned!", Destination) _Logger.Warn("Filename {0} could not be versioned. Original filename will be returned!", Destination)
_logger.Error(ex) _Logger.Error(ex)
Return Destination Return Destination
End Try End Try
End Function End Function
@ -177,29 +195,29 @@ Public Class File
ToList() ToList()
If oFiles.Count = 0 Then If oFiles.Count = 0 Then
_logger.Debug("No files found that match the criterias.") _Logger.Debug("No files found that match the criterias.")
Return True Return True
End If End If
_logger.Debug("Deleting old files (Found {0}).", oFiles.Count) _Logger.Debug("Deleting old files (Found {0}).", oFiles.Count)
For Each oFile As FileInfo In oFiles For Each oFile As FileInfo In oFiles
Try Try
oFile.Delete() oFile.Delete()
Catch ex As Exception Catch ex As Exception
If ContinueOnError = False Then If ContinueOnError = False Then
_logger.Warn("Deleting files was aborted at file {0}.", oFile.FullName) _Logger.Warn("Deleting files was aborted at file {0}.", oFile.FullName)
Return False Return False
End If End If
oUnableToDeleteCounter = oUnableToDeleteCounter + 1 oUnableToDeleteCounter = oUnableToDeleteCounter + 1
_logger.Warn("File {0} could not be deleted!") _Logger.Warn("File {0} could not be deleted!")
End Try End Try
Next Next
If oUnableToDeleteCounter > 0 Then If oUnableToDeleteCounter > 0 Then
_logger.Debug("Old files partially removed. {0} files could not be removed.", oUnableToDeleteCounter) _Logger.Debug("Old files partially removed. {0} files could not be removed.", oUnableToDeleteCounter)
Else Else
_logger.Debug("Old files removed.") _Logger.Debug("Old files removed.")
End If End If
Return True Return True
@ -256,27 +274,27 @@ Public Class File
Public Function CreateDirectory(DirectoryPath As String, Optional TestWriteAccess As Boolean = True) As String Public Function CreateDirectory(DirectoryPath As String, Optional TestWriteAccess As Boolean = True) As String
Dim oFinalPath As String Dim oFinalPath As String
If Directory.Exists(DirectoryPath) Then If Directory.Exists(DirectoryPath) Then
_logger.Debug("Directory {0} already exists. Skipping.", DirectoryPath) _Logger.Debug("Directory {0} already exists. Skipping.", DirectoryPath)
oFinalPath = DirectoryPath oFinalPath = DirectoryPath
Else Else
Try Try
Directory.CreateDirectory(DirectoryPath) Directory.CreateDirectory(DirectoryPath)
oFinalPath = DirectoryPath oFinalPath = DirectoryPath
Catch ex As Exception Catch ex As Exception
_logger.Error(ex) _Logger.Error(ex)
_logger.Warn("Directory {0} could not be created. Temp path will be used instead.", DirectoryPath) _Logger.Warn("Directory {0} could not be created. Temp path will be used instead.", DirectoryPath)
oFinalPath = Path.GetTempPath() oFinalPath = Path.GetTempPath()
End Try End Try
End If End If
If TestWriteAccess AndAlso Not TestPathIsWritable(DirectoryPath) Then If TestWriteAccess AndAlso Not TestPathIsWritable(DirectoryPath) Then
_logger.Warn("Directory {0} is not writable. Temp path will be used instead.", DirectoryPath) _Logger.Warn("Directory {0} is not writable. Temp path will be used instead.", DirectoryPath)
oFinalPath = Path.GetTempPath() oFinalPath = Path.GetTempPath()
Else Else
oFinalPath = DirectoryPath oFinalPath = DirectoryPath
End If End If
_logger.Debug("Using path {0}", oFinalPath) _Logger.Debug("Using path {0}", oFinalPath)
Return oFinalPath Return oFinalPath
End Function End Function