singrdk/base/Kernel/Singularity.Directory/DirectoryService.sg

562 lines
20 KiB
Plaintext

////////////////////////////////////////////////////////////////////////////////
//
// 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<IoMemFSContract.Imp:Ready> ioFSImpRef;
private static DirNode! rootDir;
internal static Process processForWorkerThreads;
/// <summary>
/// The provider of access control lists for objects
/// in this namespace.
/// </summary>
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<IoMemFSContract.Imp:Ready>(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()
{
}
}
}