562 lines
20 KiB
Plaintext
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()
|
||
|
{
|
||
|
}
|
||
|
}
|
||
|
}
|