Implement Qualcomm Sahara VIP and fix a few bugs

* Qualcomm Sahara VIP
* Project Cleanup
* Allow unlocking an already unlocked phone
This commit is contained in:
Gustave Monce
2021-08-11 14:33:49 +02:00
parent 9f4c92f437
commit c5fcb1ec8d
72 changed files with 987 additions and 861 deletions
+37 -43
View File
@@ -43,8 +43,8 @@ namespace DiscUtils.Fat
private DirectoryEntry _parentEntry;
private long _parentEntryLocation;
internal Dictionary<string, string> LongFileNames_ShortKey = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
internal Dictionary<string, string> LongFileNames_LongKey = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
internal Dictionary<string, string> LongFileNames_ShortKey = new(StringComparer.OrdinalIgnoreCase);
internal Dictionary<string, string> LongFileNames_LongKey = new(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Initializes a new instance of the Directory class. Use this constructor to represent non-root directories.
@@ -81,22 +81,22 @@ namespace DiscUtils.Fat
// see http://home.teleport.com/~brainy/lfn.htm
// NOTE: we assume ordinals are ok here.
char[] chars = new char[13];
chars[0] = (char)(256 * buffer[2] + buffer[1]);
chars[1] = (char)(256 * buffer[4] + buffer[3]);
chars[2] = (char)(256 * buffer[6] + buffer[5]);
chars[3] = (char)(256 * buffer[8] + buffer[7]);
chars[4] = (char)(256 * buffer[10] + buffer[9]);
chars[0] = (char)((256 * buffer[2]) + buffer[1]);
chars[1] = (char)((256 * buffer[4]) + buffer[3]);
chars[2] = (char)((256 * buffer[6]) + buffer[5]);
chars[3] = (char)((256 * buffer[8]) + buffer[7]);
chars[4] = (char)((256 * buffer[10]) + buffer[9]);
chars[5] = (char)(256 * buffer[15] + buffer[14]);
chars[6] = (char)(256 * buffer[17] + buffer[16]);
chars[7] = (char)(256 * buffer[19] + buffer[18]);
chars[8] = (char)(256 * buffer[21] + buffer[20]);
chars[9] = (char)(256 * buffer[23] + buffer[22]);
chars[10] = (char)(256 * buffer[25] + buffer[24]);
chars[5] = (char)((256 * buffer[15]) + buffer[14]);
chars[6] = (char)((256 * buffer[17]) + buffer[16]);
chars[7] = (char)((256 * buffer[19]) + buffer[18]);
chars[8] = (char)((256 * buffer[21]) + buffer[20]);
chars[9] = (char)((256 * buffer[23]) + buffer[22]);
chars[10] = (char)((256 * buffer[25]) + buffer[24]);
chars[11] = (char)(256 * buffer[29] + buffer[28]);
chars[12] = (char)(256 * buffer[31] + buffer[30]);
string chunk = new string(chars);
chars[11] = (char)((256 * buffer[29]) + buffer[28]);
chars[12] = (char)((256 * buffer[31]) + buffer[30]);
string chunk = new(chars);
int zero = chunk.IndexOf('\0');
return zero >= 0 ? chunk.Substring(0, zero) : chunk;
}
@@ -133,10 +133,7 @@ namespace DiscUtils.Fat
set
{
if (_parent != null)
{
_parent.UpdateEntry(_parentId, value);
}
_parent?.UpdateEntry(_parentId, value);
}
}
@@ -195,7 +192,7 @@ namespace DiscUtils.Fat
public DirectoryEntry[] GetDirectories()
{
List<DirectoryEntry> dirs = new List<DirectoryEntry>(_entries.Count);
List<DirectoryEntry> dirs = new(_entries.Count);
foreach (DirectoryEntry dirEntry in _entries.Values)
{
if ((dirEntry.Attributes & FatAttributes.Directory) != 0)
@@ -209,7 +206,7 @@ namespace DiscUtils.Fat
public DirectoryEntry[] GetFiles()
{
List<DirectoryEntry> files = new List<DirectoryEntry>(_entries.Count);
List<DirectoryEntry> files = new(_entries.Count);
foreach (DirectoryEntry dirEntry in _entries.Values)
{
if ((dirEntry.Attributes & (FatAttributes.Directory | FatAttributes.VolumeId)) == 0)
@@ -261,15 +258,14 @@ namespace DiscUtils.Fat
{
try
{
uint firstCluster;
if (!_fileSystem.Fat.TryGetFreeCluster(out firstCluster))
if (!_fileSystem.Fat.TryGetFreeCluster(out uint firstCluster))
{
throw new IOException("Failed to allocate first cluster for new directory");
}
_fileSystem.Fat.SetEndOfChain(firstCluster);
DirectoryEntry newEntry = new DirectoryEntry(_fileSystem.FatOptions, name, FatAttributes.Directory, _fileSystem.FatVariant);
DirectoryEntry newEntry = new(_fileSystem.FatOptions, name, FatAttributes.Directory, _fileSystem.FatVariant);
newEntry.FirstCluster = firstCluster;
newEntry.CreationTime = _fileSystem.ConvertFromUtc(DateTime.UtcNow);
newEntry.LastWriteTime = newEntry.CreationTime;
@@ -297,11 +293,11 @@ namespace DiscUtils.Fat
throw new IOException("Directory entry already exists");
}
DirectoryEntry newEntry = new DirectoryEntry(newChild.ParentsChildEntry);
DirectoryEntry newEntry = new(newChild.ParentsChildEntry);
newEntry.Name = name;
AddEntry(newEntry);
DirectoryEntry newParentEntry = new DirectoryEntry(SelfEntry);
DirectoryEntry newParentEntry = new(SelfEntry);
newParentEntry.Name = FileName.ParentEntryName;
newChild.ParentEntry = newParentEntry;
}
@@ -367,7 +363,7 @@ namespace DiscUtils.Fat
else if ((mode == FileMode.OpenOrCreate || mode == FileMode.CreateNew || mode == FileMode.Create) && !exists)
{
// Create new file
DirectoryEntry newEntry = new DirectoryEntry(_fileSystem.FatOptions, name, FatAttributes.Archive, _fileSystem.FatVariant);
DirectoryEntry newEntry = new(_fileSystem.FatOptions, name, FatAttributes.Archive, _fileSystem.FatVariant);
newEntry.FirstCluster = 0; // i.e. Zero-length
newEntry.CreationTime = _fileSystem.ConvertFromUtc(DateTime.UtcNow);
newEntry.LastWriteTime = newEntry.CreationTime;
@@ -421,7 +417,7 @@ namespace DiscUtils.Fat
{
DirectoryEntry entry = _entries[id];
DirectoryEntry copy = new DirectoryEntry(entry);
DirectoryEntry copy = new(entry);
copy.Name = entry.Name.Deleted();
_dirStream.Position = id;
copy.WriteTo(_dirStream);
@@ -466,7 +462,7 @@ namespace DiscUtils.Fat
while (_dirStream.Position < _dirStream.Length)
{
long streamPos = _dirStream.Position;
DirectoryEntry entry = new DirectoryEntry(_fileSystem.FatOptions, _dirStream, _fileSystem.FatVariant);
DirectoryEntry entry = new(_fileSystem.FatOptions, _dirStream, _fileSystem.FatVariant);
if (entry.Attributes == (FatAttributes.ReadOnly | FatAttributes.Hidden | FatAttributes.System | FatAttributes.VolumeId))
{
@@ -542,20 +538,18 @@ namespace DiscUtils.Fat
private void PopulateNewChildDirectory(DirectoryEntry newEntry)
{
// Populate new directory with initial (special) entries. First one is easy, just change the name!
using (ClusterStream stream = new ClusterStream(_fileSystem, FileAccess.Write, newEntry.FirstCluster, uint.MaxValue))
{
// First is the self-referencing entry...
DirectoryEntry selfEntry = new DirectoryEntry(newEntry);
selfEntry.Name = FileName.SelfEntryName;
selfEntry.WriteTo(stream);
using ClusterStream stream = new(_fileSystem, FileAccess.Write, newEntry.FirstCluster, uint.MaxValue);
// First is the self-referencing entry...
DirectoryEntry selfEntry = new(newEntry);
selfEntry.Name = FileName.SelfEntryName;
selfEntry.WriteTo(stream);
// Second is a clone of our self entry (i.e. parent) - though dates are odd...
DirectoryEntry parentEntry = new DirectoryEntry(SelfEntry);
parentEntry.Name = FileName.ParentEntryName;
parentEntry.CreationTime = newEntry.CreationTime;
parentEntry.LastWriteTime = newEntry.LastWriteTime;
parentEntry.WriteTo(stream);
}
// Second is a clone of our self entry (i.e. parent) - though dates are odd...
DirectoryEntry parentEntry = new(SelfEntry);
parentEntry.Name = FileName.ParentEntryName;
parentEntry.CreationTime = newEntry.CreationTime;
parentEntry.LastWriteTime = newEntry.LastWriteTime;
parentEntry.WriteTo(stream);
}
private void Dispose(bool disposing)
@@ -40,7 +40,7 @@ namespace DiscUtils.Fat
/// <summary>
/// The Epoch for FAT file systems (1st Jan, 1980).
/// </summary>
public static readonly DateTime Epoch = new DateTime(1980, 1, 1);
public static readonly DateTime Epoch = new(1980, 1, 1);
private TimeConverter _timeConverter;
private Stream _data;
@@ -158,7 +158,7 @@ namespace DiscUtils.Fat
{
_dirCache = new Dictionary<uint, Directory>();
if (parameters != null && parameters.TimeConverter != null)
if (parameters?.TimeConverter != null)
{
_timeConverter = parameters.TimeConverter;
}
@@ -196,13 +196,13 @@ namespace DiscUtils.Fat
{
get
{
switch (_type)
return _type switch
{
case FatType.Fat12: return "Microsoft FAT12";
case FatType.Fat16: return "Microsoft FAT16";
case FatType.Fat32: return "Microsoft FAT32";
default: return "Unknown FAT";
}
FatType.Fat12 => "Microsoft FAT12",
FatType.Fat16 => "Microsoft FAT16",
FatType.Fat32 => "Microsoft FAT32",
_ => "Unknown FAT",
};
}
}
@@ -463,14 +463,14 @@ namespace DiscUtils.Fat
// Write both FAT copies
uint fatSize = CalcFatSize(sectors, FatType.Fat12, 1);
byte[] fat = new byte[fatSize * Sizes.Sector];
FatBuffer fatBuffer = new FatBuffer(FatType.Fat12, fat);
FatBuffer fatBuffer = new(FatType.Fat12, fat);
fatBuffer.SetNext(0, 0xFFFFFFF0);
fatBuffer.SetEndOfChain(1);
stream.Write(fat, 0, fat.Length);
stream.Write(fat, 0, fat.Length);
// Write the (empty) root directory
uint rootDirSectors = ((224 * 32) + Sizes.Sector - 1) / Sizes.Sector;
const uint rootDirSectors = ((224 * 32) + Sizes.Sector - 1) / Sizes.Sector;
byte[] rootDir = new byte[rootDirSectors * Sizes.Sector];
stream.Write(rootDir, 0, rootDir.Length);
@@ -493,16 +493,14 @@ namespace DiscUtils.Fat
/// <returns>An object that provides access to the newly created partition file system.</returns>
public static FatFileSystem FormatPartition(VirtualDisk disk, int partitionIndex, string label)
{
using (Stream partitionStream = disk.Partitions[partitionIndex].Open())
{
return FormatPartition(
partitionStream,
label,
disk.Geometry,
(int)disk.Partitions[partitionIndex].FirstSector,
(int)(1 + disk.Partitions[partitionIndex].LastSector - disk.Partitions[partitionIndex].FirstSector),
0);
}
using Stream partitionStream = disk.Partitions[partitionIndex].Open();
return FormatPartition(
partitionStream,
label,
disk.Geometry,
(int)disk.Partitions[partitionIndex].FirstSector,
(int)(1 + disk.Partitions[partitionIndex].LastSector - disk.Partitions[partitionIndex].FirstSector),
0);
}
/// <summary>
@@ -612,7 +610,7 @@ namespace DiscUtils.Fat
*/
byte[] fat = new byte[CalcFatSize((uint)sectorCount, fatType, sectorsPerCluster) * Sizes.Sector];
FatBuffer fatBuffer = new FatBuffer(fatType, fat);
FatBuffer fatBuffer = new(fatType, fat);
fatBuffer.SetNext(0, 0xFFFFFFF8);
fatBuffer.SetEndOfChain(1);
if (fatType >= FatType.Fat32)
@@ -780,8 +778,7 @@ namespace DiscUtils.Fat
return;
}
Directory parent;
long id = GetDirectoryEntry(path, out parent);
long id = GetDirectoryEntry(path, out Directory parent);
DirectoryEntry dirEntry = parent.GetEntry(id);
FatAttributes newFatAttr = (FatAttributes)newValue;
@@ -836,7 +833,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.CreationTime = newTime; });
UpdateDirEntry(path, (e) => e.CreationTime = newTime);
}
/// <summary>
@@ -871,7 +868,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.CreationTime = ConvertFromUtc(newTime); });
UpdateDirEntry(path, (e) => e.CreationTime = ConvertFromUtc(newTime));
}
/// <summary>
@@ -906,7 +903,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.LastAccessTime = newTime; });
UpdateDirEntry(path, (e) => e.LastAccessTime = newTime);
}
/// <summary>
@@ -941,7 +938,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.LastAccessTime = ConvertFromUtc(newTime); });
UpdateDirEntry(path, (e) => e.LastAccessTime = ConvertFromUtc(newTime));
}
/// <summary>
@@ -976,7 +973,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.LastWriteTime = newTime; });
UpdateDirEntry(path, (e) => e.LastWriteTime = newTime);
}
/// <summary>
@@ -1011,7 +1008,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.LastWriteTime = ConvertFromUtc(newTime); });
UpdateDirEntry(path, (e) => e.LastWriteTime = ConvertFromUtc(newTime));
}
/// <summary>
@@ -1032,8 +1029,7 @@ namespace DiscUtils.Fat
/// <param name="overwrite">Whether to permit over-writing of an existing file.</param>
public override void CopyFile(string sourceFile, string destinationFile, bool overwrite)
{
Directory sourceDir;
long sourceEntryId = GetDirectoryEntry(sourceFile, out sourceDir);
long sourceEntryId = GetDirectoryEntry(sourceFile, out Directory sourceDir);
if (sourceDir == null || sourceEntryId < 0)
{
@@ -1047,12 +1043,11 @@ namespace DiscUtils.Fat
throw new IOException("The source file is a directory");
}
DirectoryEntry newEntry = new DirectoryEntry(sourceEntry);
DirectoryEntry newEntry = new(sourceEntry);
newEntry.Name = FileName.FromPath(destinationFile, FatOptions.FileNameEncoding);
newEntry.FirstCluster = 0;
Directory destDir;
long destEntryId = GetDirectoryEntry(destinationFile, out destDir);
long destEntryId = GetDirectoryEntry(destinationFile, out Directory destDir);
if (destDir == null)
{
@@ -1095,11 +1090,9 @@ namespace DiscUtils.Fat
destEntryId = destDir.AddEntry(newEntry);
// Copy the contents...
using (Stream sourceStream = new FatFileStream(this, sourceDir, sourceEntryId, FileAccess.Read),
destStream = new FatFileStream(this, destDir, destEntryId, FileAccess.Write))
{
StreamUtilities.PumpStreams(sourceStream, destStream);
}
using Stream sourceStream = new FatFileStream(this, sourceDir, sourceEntryId, FileAccess.Read),
destStream = new FatFileStream(this, destDir, destEntryId, FileAccess.Write);
StreamUtilities.PumpStreams(sourceStream, destStream);
}
/// <summary>
@@ -1151,8 +1144,7 @@ namespace DiscUtils.Fat
throw new IOException("Unable to delete non-empty directory");
}
Directory parent;
long id = GetDirectoryEntry(path, out parent);
long id = GetDirectoryEntry(path, out Directory parent);
if (parent == null && id == 0)
{
throw new IOException("Unable to delete root directory");
@@ -1175,8 +1167,7 @@ namespace DiscUtils.Fat
/// <param name="path">The path of the file to delete.</param>
public override void DeleteFile(string path)
{
Directory parent;
long id = GetDirectoryEntry(path, out parent);
long id = GetDirectoryEntry(path, out Directory parent);
if (parent == null || id < 0)
{
throw new FileNotFoundException("No such file", path);
@@ -1261,7 +1252,7 @@ namespace DiscUtils.Fat
}
DirectoryEntry[] entries = dir.GetDirectories();
List<string> dirs = new List<string>(entries.Length);
List<string> dirs = new(entries.Length);
foreach (DirectoryEntry dirEntry in entries)
{
dirs.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
@@ -1282,7 +1273,7 @@ namespace DiscUtils.Fat
{
Regex re = Utilities.ConvertWildcardsToRegEx(searchPattern);
List<string> dirs = new List<string>();
List<string> dirs = new();
DoSearch(dirs, path, re, searchOption == SearchOption.AllDirectories, true, false);
return dirs.ToArray();
}
@@ -1297,7 +1288,7 @@ namespace DiscUtils.Fat
Directory dir = GetDirectory(path);
DirectoryEntry[] entries = dir.GetFiles();
List<string> files = new List<string>(entries.Length);
List<string> files = new(entries.Length);
foreach (DirectoryEntry dirEntry in entries)
{
files.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
@@ -1318,7 +1309,7 @@ namespace DiscUtils.Fat
{
Regex re = Utilities.ConvertWildcardsToRegEx(searchPattern);
List<string> results = new List<string>();
List<string> results = new();
DoSearch(results, path, re, searchOption == SearchOption.AllDirectories, false, true);
return results.ToArray();
}
@@ -1333,7 +1324,7 @@ namespace DiscUtils.Fat
Directory dir = GetDirectory(path);
DirectoryEntry[] entries = dir.Entries;
List<string> result = new List<string>(entries.Length);
List<string> result = new(entries.Length);
foreach (DirectoryEntry dirEntry in entries)
{
result.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
@@ -1356,7 +1347,7 @@ namespace DiscUtils.Fat
Directory dir = GetDirectory(path);
DirectoryEntry[] entries = dir.Entries;
List<string> result = new List<string>(entries.Length);
List<string> result = new(entries.Length);
foreach (DirectoryEntry dirEntry in entries)
{
if (re.IsMatch(dirEntry.Name.GetSearchName(FatOptions.FileNameEncoding)))
@@ -1387,8 +1378,7 @@ namespace DiscUtils.Fat
}
}
Directory destParent;
long destId = GetDirectoryEntry(destinationDirectoryName, out destParent);
long destId = GetDirectoryEntry(destinationDirectoryName, out Directory destParent);
if (destParent == null)
{
throw new DirectoryNotFoundException("Target directory doesn't exist");
@@ -1398,8 +1388,7 @@ namespace DiscUtils.Fat
throw new IOException("Target directory already exists");
}
Directory sourceParent;
long sourceId = GetDirectoryEntry(sourceDirectoryName, out sourceParent);
long sourceId = GetDirectoryEntry(sourceDirectoryName, out Directory sourceParent);
if (sourceParent == null || sourceId < 0)
{
throw new IOException("Source directory doesn't exist");
@@ -1417,8 +1406,7 @@ namespace DiscUtils.Fat
/// <param name="overwrite">Whether to permit a destination file to be overwritten.</param>
public override void MoveFile(string sourceName, string destinationName, bool overwrite)
{
Directory sourceDir;
long sourceEntryId = GetDirectoryEntry(sourceName, out sourceDir);
long sourceEntryId = GetDirectoryEntry(sourceName, out Directory sourceDir);
if (sourceDir == null || sourceEntryId < 0)
{
@@ -1432,11 +1420,10 @@ namespace DiscUtils.Fat
throw new IOException("The source file is a directory");
}
DirectoryEntry newEntry = new DirectoryEntry(sourceEntry);
DirectoryEntry newEntry = new(sourceEntry);
newEntry.Name = FileName.FromPath(destinationName, FatOptions.FileNameEncoding);
Directory destDir;
long destEntryId = GetDirectoryEntry(destinationName, out destDir);
long destEntryId = GetDirectoryEntry(destinationName, out Directory destDir);
if (destDir == null)
{
@@ -1492,14 +1479,13 @@ namespace DiscUtils.Fat
internal Directory GetDirectory(string path)
{
Directory parent;
if (string.IsNullOrEmpty(path) || path == "\\")
{
return _rootDir;
}
long id = GetDirectoryEntry(_rootDir, path, out parent);
long id = GetDirectoryEntry(_rootDir, path, out Directory parent);
if (id >= 0)
{
return GetDirectory(parent, id);
@@ -1524,8 +1510,7 @@ namespace DiscUtils.Fat
}
// If we have this one cached, return it
Directory result;
if (_dirCache.TryGetValue(dirEntry.FirstCluster, out result))
if (_dirCache.TryGetValue(dirEntry.FirstCluster, out Directory result))
{
return result;
}
@@ -1549,9 +1534,8 @@ namespace DiscUtils.Fat
internal DirectoryEntry GetDirectoryEntry(string path)
{
Directory parent;
long id = GetDirectoryEntry(_rootDir, path, out parent);
long id = GetDirectoryEntry(_rootDir, path, out Directory parent);
if (parent == null || id < 0)
{
return null;
@@ -1707,7 +1691,7 @@ namespace DiscUtils.Fat
private static uint CalcFatSize(uint sectors, FatType fatType, byte sectorsPerCluster)
{
uint numClusters = (uint)(sectors / sectorsPerCluster);
uint fatBytes = (numClusters * (ushort)fatType) / 8;
uint fatBytes = numClusters * (ushort)fatType / 8;
return (fatBytes + Sizes.Sector - 1) / Sizes.Sector;
}
@@ -1894,8 +1878,7 @@ namespace DiscUtils.Fat
else
{
// Long filename support - translate long filename lookup to short filename
string ShortName;
if (dir.LongFileNames_LongKey.TryGetValue(pathEntries[pathOffset], out ShortName))
if (dir.LongFileNames_LongKey.TryGetValue(pathEntries[pathOffset], out string ShortName))
pathEntries[pathOffset] = ShortName;
entryId = dir.FindEntry(new FileName(pathEntries[pathOffset], FatOptions.FileNameEncoding));
@@ -1955,8 +1938,7 @@ namespace DiscUtils.Fat
private void UpdateDirEntry(string path, EntryUpdateAction action)
{
Directory parent;
long id = GetDirectoryEntry(path, out parent);
long id = GetDirectoryEntry(path, out Directory parent);
DirectoryEntry entry = parent.GetEntry(id);
action(entry);
parent.UpdateEntry(id, entry);
@@ -1973,7 +1955,7 @@ namespace DiscUtils.Fat
/// <summary>
/// Size of the Filesystem in bytes
/// </summary>
public override long Size { get { return ((TotalSectors - ReservedSectorCount - (FatSize * FatCount)) * BytesPerSector); } }
public override long Size { get { return (TotalSectors - ReservedSectorCount - (FatSize * FatCount)) * BytesPerSector; } }
/// <summary>
/// Used space of the Filesystem in bytes
@@ -1991,7 +1973,7 @@ namespace DiscUtils.Fat
usedCluster++;
}
}
return (usedCluster * SectorsPerCluster * BytesPerSector);
return usedCluster * SectorsPerCluster * BytesPerSector;
}
}
@@ -2016,8 +1998,7 @@ namespace DiscUtils.Fat
if (dir == null)
return fileName;
string lfn;
if (dir.LongFileNames_ShortKey.TryGetValue(Path.GetFileName(shortFullPath), out lfn))
if (dir.LongFileNames_ShortKey.TryGetValue(Path.GetFileName(shortFullPath), out string lfn))
return lfn;
return fileName;