using System;
using System.Collections.Generic;
using System.IO;
using System.ServiceProcess;
using System.Threading.Tasks;
namespace TGServerService
{
static class Program
{
///
/// Entry point to the program
///
static void Main() {
using (var S = new Service())
ServiceBase.Run(S);
}
///
/// Copy a file from to , but first ensure the destination directory exists
///
/// The source file
/// The destination file
/// If , will overwrite if it is a file. Otherwise, if exists, an exception will be thrown
public static void CopyFileForceDirectories(string source, string dest, bool overwrite)
{
try
{
Directory.CreateDirectory(Path.GetDirectoryName(dest));
}
catch { } //we don't care if the above errors
File.Copy(source, dest, overwrite); //if this throws errors thats all we care about
}
//http://stackoverflow.com/questions/1701457/directory-delete-doesnt-work-access-denied-error-but-under-windows-explorer-it
///
/// Recursive directory deleter
///
/// The directory to delete
/// If , an empty will remain instead of being deleted fully. Incompatible with
/// If any files or directories in the root level of match anything in this of s, they won't be deleted. Incompatible with
public static async void DeleteDirectory(string path, bool ContentsOnly = false, IList excludeRoot = null)
{
var di = new DirectoryInfo(path);
if (!di.Exists)
return;
if (excludeRoot != null)
for (var I = 0; I < excludeRoot.Count; ++I)
excludeRoot[I] = excludeRoot[I].ToLower();
if (CheckDeleteSymlinkDir(di))
return;
await NormalizeAndDelete(di, excludeRoot, false);
if (!ContentsOnly)
{
if (excludeRoot != null && excludeRoot.Count > 0)
throw new Exception("Cannot fully delete folder with exclusions specified!");
di.Delete(true);
}
}
///
/// Properly unlinks directory if it is a symlink
///
/// for the directory in question
/// if was a symlink and deleted, otherwise
static bool CheckDeleteSymlinkDir(DirectoryInfo di)
{
if (!di.Attributes.HasFlag(FileAttributes.Directory))
{ //this is probably a symlink
Directory.Delete(di.FullName);
return true;
}
return false;
}
///
/// Recursively empty a directory
///
/// of the directory to empty
/// Lowercase file and directory names to skip while emptying this level. Not passed forward
/// If , will be deleted before the function exits
static async Task NormalizeAndDelete(DirectoryInfo dir, IList excludeRoot, bool deleteRoot)
{
var tasks = new List { Task.Factory.StartNew(() =>
{
foreach (var file in dir.GetFiles())
{
if (excludeRoot != null && excludeRoot.Contains(file.Name.ToLower()))
continue;
file.Attributes = FileAttributes.Normal;
file.Delete();
}
}) };
foreach (var subDir in dir.GetDirectories())
{
if (excludeRoot != null && excludeRoot.Contains(subDir.Name.ToLower()))
continue;
if (CheckDeleteSymlinkDir(subDir))
continue;
tasks.Add(NormalizeAndDelete(subDir, null, true));
}
await Task.WhenAll(tasks);
if(deleteRoot)
dir.Delete(true);
}
///
/// Recusively copy a directory
///
/// The directory to copy
/// The destination directory
/// List of files and directories to ignore while copying
/// If no error will be thrown if does not exist
public static async void CopyDirectory(string sourceDirName, string destDirName, IList ignore = null, bool ignoreIfNotExists = false)
{
IList realIgnore;
if (ignore != null)
{
realIgnore = new List();
foreach (var I in ignore)
realIgnore.Add(I.ToLower());
}
else
realIgnore = null;
await CopyDirectoryImpl(sourceDirName, destDirName, realIgnore, ignoreIfNotExists);
}
///
/// Recusively copy a directory
///
/// The directory to copy
/// The destination directory
/// List of lowercase files and directories to ignore while copying
/// If no error will be thrown if does not exist
static async Task CopyDirectoryImpl(string sourceDirName, string destDirName, IList ignore, bool ignoreIfNotExists) {
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
if (ignoreIfNotExists)
return;
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
DirectoryInfo[] dirs = dir.GetDirectories();
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
if (ignore != null && ignore.Contains(file.Name.ToLower()))
continue;
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, true);
}
var tasks = new List();
// copy them and their contents to new location.
foreach (DirectoryInfo subdir in dirs)
{
if (ignore != null && ignore.Contains(subdir.Name.ToLower()))
continue;
string temppath = Path.Combine(destDirName, subdir.Name);
tasks.Add(CopyDirectoryImpl(subdir.FullName, temppath, ignore, false));
}
await Task.WhenAll(tasks);
}
///
/// Properly escapes characters for a BYOND Topic() packet. See http://www.byond.com/docs/ref/info.html#/proc/list2params
///
/// The to sanitize
/// The sanitized string
public static string SanitizeTopicString(string input)
{
return input.Replace("%", "%25").Replace("=", "%3d").Replace(";", "%3b").Replace("&", "%26").Replace("+", "%2b");
}
///
/// Normalizes different versions of a path
///
/// The path to normalize
/// The normalized path
public static string NormalizePath(string path)
{
return Path.GetFullPath(new Uri(path).LocalPath)
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
.ToUpperInvariant();
}
}
}