//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: Directory.sg // // Note: // using System; using System.Text; using System.Collections; using System.Threading; using System.Text; using Microsoft.SingSharp; using Microsoft.Singularity; using Microsoft.Singularity.Io; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Directory; using Microsoft.Singularity.Memory; using Microsoft.Singularity.Xml; using Microsoft.Singularity.Security ;using Microsoft.Singularity.Security.SDS; using Microsoft.Singularity.Loader; namespace Microsoft.Singularity.Directory { [CLSCompliant(false)] public enum DirectoryEvent : ushort { DoBind = 1, DoGetAttributes = 2, DoCreateDirectory = 3, DoCreateFile = 4, DoDeleteDirectory = 5, DoDeleteLink = 6, DoGetLinkValue = 7, DoCreateLink = 8, } public class DirectoryService { public const string ManifestFile = "manifest"; public const string ExecutableExtension = ".x86"; public const string ManifestExtension = ".manifest"; public const string ExecutablesNamespace = "init"; private static TRef ioFSImpRef; private static DirNode! rootDir; internal static Process processForWorkerThreads; /// /// The provider of access control lists for objects /// in this namespace. /// public static void Initialize(XmlNode! config) { NotificationManager.Initialize(); //RootDir = new RootDirectory("/"); ISdsAcl! aclT = new SdsAclImpl(); AclCore core = new AclCore("DS_Acl", new DirAclCoreSupport()); rootDir = new DirNode("/", core, aclT); processForWorkerThreads = Thread.CurrentProcess; InstallLoadedApplications(config); InstallOtherFiles(config); InstallGroups(config); InstallAcls(config, aclT); } public static void StartNotificationThread() { NotificationManager.StartNotificationThread(); } public static DirectoryServiceContract.Imp:Ready! NewClientEndpoint() { #if !SINGULARITY_PROCESS DirectoryServiceContract.Imp! c; DirectoryServiceContract.Exp! s; DirectoryServiceContract.NewChannel(out c, out s); DirectoryServiceWorker.Create(rootDir, s); c.RecvSuccess(); return c; #else return null; #endif } public static unsafe SharedHeap.Allocation * NewClientEndpointEx() { // This sequence tells the ownership checker that we transfer // the obligation to the result. DirectoryServiceContract.Imp! imp = NewClientEndpoint(); SharedHeap.Allocation* result = (SharedHeap.Allocation*)imp; return result; } /*************************************************************************************/ #region Constants // // consts for accessing Xml tags and attributes // // tags describing entries in the binder const string FileListXmlTag = "files"; const string FileEntryXmlTag = "file"; const string FileNameXmlAttribute = "name"; const string BinderPositionXmlAttribute = "id"; const string ManifestBinderPositionXmlAttribute = "manifestId"; const string IsExecutableXmlAttribute = "executable"; const string IsManifestXmlAttribute = "manifest"; // security tags const string GroupListXmlTag = "groups"; const string GroupEntryXmlTag = "group"; const string AclListXmlTag = "acls"; const string AclEntryXmlTag = "acl"; const string AclEntryPathTag = "path"; const string AclEntryThisTag = "this"; const string AclEntryInheritedTag = "inherited"; const string GroupListRootXmlAttribute = "root"; const string GroupEntryPathXmlAttribute = "path"; const string GroupEntryDescriptionXmlAttribute = "description"; const string NamespaceParametersTag = "namespace"; const string ProxyChannelsAttribute = "proxyChannels"; const int DefaultProxyChannels = 10; #endregion private static void InstallLoadedApplications(XmlNode! config) { // get all files to register from the xml XmlNode filesConfig = config.GetChild(FileListXmlTag); if (filesConfig == null) { return; } ErrorCode error; if (!rootDir.CreateDirectory(DirectoryService.ExecutablesNamespace, out error)) { throw new Exception("Cannot create executables directory"); } StringBuilder sb = new StringBuilder(DirectoryService.ExecutablesNamespace.Length + 1); sb.Append("/"); sb.Append(DirectoryService.ExecutablesNamespace); DirNode root = rootDir.FindDirectory(sb); if (root == null) { throw new Exception("Cannot find executables directory"); } foreach (XmlNode! file in filesConfig.Children) { if (file.Name != FileEntryXmlTag) { continue; } bool executable = file.GetAttribute(IsExecutableXmlAttribute, false); bool manifest = file.GetAttribute(IsManifestXmlAttribute, false); int order = file.GetAttribute(BinderPositionXmlAttribute, -1); if ((!executable && !manifest) || order == -1) { // skip non-manifest and non-executable files. continue; } // get attributes. string! name = (!) file.GetAttribute(FileNameXmlAttribute, ""); // remove .x86 extension. name = (!)name.Replace(".x86", ""); int manifestOrder = file.GetAttribute( ManifestBinderPositionXmlAttribute, -1); IoMemory memory = Resources.GetLoadedImageMemory(order); if (memory == null) { DebugStub.WriteLine("Failure loading name={0} order={1}", __arglist(name, order)); throw new Exception("Cannot load image"); } if (executable) { name = (name + DirectoryService.ExecutableExtension); } string folderName = GetFolderName(name); if (folderName != null) { // this is an application. // First register the binary in the init directory // Then register the associated manifest by inspecting the manifestIndex tag // (this should be imageIndex + 1) if (root.CreateDirectory(folderName, out error)) { // obtain the containing directory StringBuilder p = new StringBuilder(folderName.Length + 1); p.Append("/"); p.Append(folderName); DirNode! dir = (!)root.FindDirectory(p); // register the executable's image dir.RegisterIoMemory(name, memory); // if we have a manifest, install it. if (manifestOrder != -1 ) { //DebugStub.WriteLine("loading manifest for {0}, binder index={1}", // __arglist(folderName,manifestOrder)); IoMemory manMemory = Resources.GetLoadedImageMemory(manifestOrder); if (manMemory == null) { DebugStub.WriteLine("Failure loading manifest. name={0} manifestOrder={1}", __arglist(name, manifestOrder)); throw new Exception("Cannot load manifest"); } dir.RegisterIoMemory(DirectoryService.ManifestFile, manMemory); } } } else { // skip manifests (processed above) if (!name.EndsWith(DirectoryService.ManifestExtension)) { // this is a plain old file root.RegisterIoMemory(name, memory); } } } } private static void InstallOtherFiles(XmlNode! config) { // get all files to register from the xml XmlNode filesConfig = config.GetChild(FileListXmlTag); if (filesConfig == null) { return; } ErrorCode error; StringBuilder sb = new StringBuilder(DirectoryService.ExecutablesNamespace.Length + 1); sb.Append("/"); sb.Append(DirectoryService.ExecutablesNamespace); DirNode root = rootDir.FindDirectory(sb); if (root == null) { throw new Exception("Cannot find executables directory"); } foreach (XmlNode! file in filesConfig.Children) { if (file.Name != FileEntryXmlTag) { continue; } bool executable = file.GetAttribute(IsExecutableXmlAttribute, false); bool manifest = file.GetAttribute(IsManifestXmlAttribute, false); int order = file.GetAttribute(BinderPositionXmlAttribute, -1); if (executable || manifest || order == -1) { // skip executables, manifests, and non-existent files. continue; } string! name = (!)(file.GetAttribute(FileNameXmlAttribute, "")); IoMemory memory = Resources.GetLoadedImageMemory(order); if (memory == null) { DebugStub.WriteLine("Failure loading name={0} order={1}", __arglist(name, order)); throw new Exception("Cannot load image"); } // register the executable's image root.RegisterIoMemory(name, memory); } } private static void InstallGroups(XmlNode! config) { UTF8Encoding encoder = new UTF8Encoding(); // get all group definitions to register from the xml XmlNode groupsConfig = config.GetChild(GroupListXmlTag); if (groupsConfig == null) { return; } DirNode! groot = rootDir; foreach (XmlNode! group in groupsConfig.Children) { if (group.Name != GroupEntryXmlTag) { continue; } string! path = (!)group.GetAttribute(GroupEntryPathXmlAttribute, ""); string! desc = (!)group.GetAttribute(GroupEntryDescriptionXmlAttribute, ""); // DebugStub.WriteLine("Current group: name: {0}, description: {1}", // __arglist(path, desc)); if (!path.Equals("")) { int length = path.Length; int index = path.LastIndexOf('/'); if (index != length-1) { string! name = (!)path.Substring(index+1); DirNode dir = GetContainingFolder(groot, path, false); if (dir != null) { byte[] bytes = encoder.GetBytes(desc); if (bytes == null) { continue; } int size = bytes.Length; IoMemory memory = IoMemory.AllocateRealFixed((UIntPtr)size); if (memory != null) { // DebugStub.WriteLine("wrote the bytes"); memory.Write8(0, bytes); // register the group definition dir.RegisterIoMemory(name, memory); // DebugStub.WriteLine("Registered the memory"); } } else { // DebugStub.WriteLine("Could not get the containing folder"); } } } } } private static void InstallAcls(XmlNode! config, ISdsAcl! aclT) { // read the rules section from the config XmlNode node = config.GetChild(AclListXmlTag); if (node == null) { return; } foreach (XmlNode! rule in node.Children) { if (rule.Name != AclEntryXmlTag) { continue; } string path = (!)rule.GetAttribute(AclEntryPathTag, null); if (path == null) { continue; } string aclThis = rule.GetAttribute(AclEntryThisTag, null); if (aclThis == null) { continue; } string aclInherited = rule.GetAttribute(AclEntryInheritedTag, null); aclT.Set(path, new Acl(aclThis, aclInherited)); } } private static string GetFolderName(string! image) { if (image.EndsWith(DirectoryService.ExecutableExtension)) { return (!)image.Substring(0, image.Length - DirectoryService.ExecutableExtension.Length); } else if (image.EndsWith(DirectoryService.ManifestExtension) || // [TODO] is the following line still correct? image.EndsWith(DirectoryService.ManifestFile)) { return null; } else { return image; } } private static DirNode GetContainingFolder(DirNode! start, string! path, bool mode) { // DebugStub.WriteLine("GetContainingFolder: Start: {0}, Path: {1}", // __arglist(start.NodeName, path)); string[] split = (!)path.Split('/'); DirNode current = start; int size; if (mode) { size = split.Length; } else { size = split.Length - 1; } for (int i = 0; i < size; i++) { // DebugStub.WriteLine("Current split: {0}", __arglist(split[i])); if (split[i] != "") { StringBuilder sb = new StringBuilder(((!)split[i]).Length + 1); sb.Append("/"); sb.Append(split[i]); // DebugStub.WriteLine("Looking up directory: /{0}", __arglist(split[i])); DirNode temp = current.FindDirectory(sb); ErrorCode error; if (temp == null) { // DebugStub.WriteLine("Directory does not exist. Trying to create"); if (current.CreateDirectory((!)split[i], out error)) { // DebugStub.WriteLine("Created the directory"); current = current.FindDirectory(sb); if (current != null) { // DebugStub.WriteLine("Found what created"); } else { return null; // DebugStub.WriteLine("Cannot find what created"); } } else { // DebugStub.WriteLine("Failed to create the directory"); return null; } } else { current = temp; } } } return current; } /////////////////////////////////////////////////////////////////////////////// // begin kernel only functions /////////////////////////////////////////////////////////////////////////////// public static bool SetIoFS([Claims]IoMemFSContract.Imp:Ready! imp) { DebugStub.WriteLine(" SetIoFs"); #if !SINGULARITY_PROCESS ioFSImpRef = new TRef(imp); return true; #else return false; #endif } public static IoMemFSContract.Imp:Ready AcquireIoFS() { #if !SINGULARITY_PROCESS if ( ioFSImpRef != null) { return ioFSImpRef.Acquire(); } else { DebugStub.Break(); } #endif return null; } public static bool ReleaseIoFS([Claims]IoMemFSContract.Imp:Ready! io) { #if !SINGULARITY_PROCESS if ( ioFSImpRef != null) { ioFSImpRef.Release(io); return true; } else { DebugStub.Break(); } #endif delete io; // this is not right. return false; } public static bool RegisterIoMemory(DirNode dirNode, string! path, IoMemory! ioMem) { #if !SINGULARITY_PROCESS if (dirNode != null) return dirNode.RegisterIoMemory(path, ioMem); return false; #else return false; #endif } public static bool CreateDirectory(DirNode node, string! path) { #if !SINGULARITY_PROCESS ErrorCode error; if (null != node) return node.CreateDirectory(path, out error); return false; #else return false; #endif } public static bool CreateSymbolicLink(DirNode node, string! path, string! val) { #if !SINGULARITY_PROCESS if (null != node) return node.CreateLink(path,val); return false; #else return false; #endif } public static DirNode FindDirectory(string! path) { #if !SINGULARITY_PROCESS if (path == "/")return rootDir; return rootDir.FindDirectory(new StringBuilder(path)); #else return null; #endif } public static DirNode FindDirectory(string! path, bool createIfNull) { if (!createIfNull) { return FindDirectory(path); } // parse the name, one directory token at a time. If the token // exists, advance to it, otherwise, create it and advance to it ErrorCode error; DirNode nexttree; DirNode! currenttree = (!) DirectoryService.FindDirectory("/"); foreach (string folder in path.Split('/')) { // don't do the first entry, as it is the root, "/", which we // already have in root if (folder != "") { StringBuilder! p = new StringBuilder("/" + folder); nexttree = currenttree.FindDirectory(p); if (nexttree == null) { currenttree.CreateDirectory((!)folder, out error); nexttree = currenttree.FindDirectory(p); } currenttree = (!) nexttree; } } return currenttree; } /////////////////////////////////////////////////////////////////////////////// // end kernel only functions /////////////////////////////////////////////////////////////////////////////// public static void Finalize() { } } }