singrdk/base/Services/Iso9660/Iso9660Service.sg

339 lines
12 KiB
Plaintext
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
// ----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ----------------------------------------------------------------------------
using System;
using System.IO;
using System.Threading;
using Microsoft.SingSharp;
using Microsoft.Singularity.Directory;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Security;
using Microsoft.Singularity.FileSystem;
using Microsoft.Singularity.Configuration;
using Microsoft.Singularity.ServiceManager;
using Iso9660;
[assembly: ApplicationPublisherAttribute("singularity.microsoft.com")]
[assembly: AssertPrivilegeAttribute("$register-privilege.localhost")]
namespace Microsoft.Singularity.FileSystem
{
[Category("Service")]
internal class ServiceParameters
{
[CustomEndpoint]
public readonly TRef<ServiceProcessContract.Exp:Starting> ControlEndpointRef;
[CustomEndpoint]
public readonly TRef<ServiceEventContract.Imp:Ready> EventEndpointRef;
reflective internal ServiceParameters();
}
public class Iso9660Service : ITracked
{
internal static int AppMain(ServiceParameters! parameters) {
ServiceProcessContract.Exp! svcontrol = ((!)parameters.ControlEndpointRef).Acquire();
ServiceEventContract.Imp! svevent = ((!)parameters.EventEndpointRef).Acquire();
Iso9660Service service = new Iso9660Service(svcontrol, svevent);
try {
service.Run();
}
finally {
service.Dispose();
}
return 0;
}
#region Data Fields
private string mountPath;
private bool mounted;
readonly string dbgprefix;
readonly ServiceProcessContract.Exp! svcontrol;
readonly ServiceEventContract.Imp! svevent;
readonly ESet<FileSystemControllerContract.Exp:Ready>! controllers =
new ESet<FileSystemControllerContract.Exp:Ready>();
readonly ArrayList/*<Iso9660Fs>*/ filesystems = new ArrayList();
#endregion
Iso9660Service(
[Claims]ServiceProcessContract.Exp! svcontrol,
[Claims]ServiceEventContract.Imp! svevent)
{
this.svcontrol = svcontrol;
this.svevent = svevent;
this.dbgprefix = "ISO9660Service: ";
this.mounted = false;
this.mountPath = null;
}
public void Dispose()
{
delete controllers;
delete svcontrol;
delete svevent;
}
void Dbg(string! line)
{
DebugStub.WriteLine(dbgprefix + line);
}
void Dbg(string! format, params object[]! args)
{
Dbg(String.Format(format, args));
}
internal void Run()
{
expose (this) {
svcontrol.SendStartSucceeded();
for (;;) {
switch receive {
case svcontrol.Connect(char[] in ExHeap expath, ServiceContract.Exp:Start! candidate):
{
if (expath != null) {
string! path = Bitter.ToString2(expath);
delete expath;
Dbg("Received 'Connect' with subpath '{0}'. This service does not support subpaths; rejecting.", path);
svcontrol.SendNakConnect(ErrorCode.NotFound, candidate);
break;
}
FileSystemControllerContract.Exp client = candidate as FileSystemControllerContract.Exp;
if (client != null) {
Dbg("Received 'Connect' with contract FileSystemControllerContract.");
svcontrol.SendAckConnect();
client.SendSuccess();
controllers.Add(client);
}
else {
Dbg("Received 'Connect', but the client did not provide a supported contract.");
svcontrol.SendNakConnect(ErrorCode.ContractNotSupported, candidate);
}
break;
}
case svcontrol.Knock():
svcontrol.SendAlive();
break;
case svcontrol.Stop():
Dbg("Service Manager has requested that this service stop.");
return;
case svcontrol.ChannelClosed():
Dbg("Service control channel has closed! Not good!");
return;
case controller.Mount(char[]! in ExHeap exdevice, char[]! in ExHeap expath) in controllers:
{
string! device = Bitter.ToString2(exdevice);
string! path = Bitter.ToString2(expath);
delete exdevice;
delete expath;
Dbg("Received mount request, device '{0}' mount path '{1}'.", device, path);
ErrorCode error = ProcessMountRequest(device, path);
if (error == ErrorCode.NoError) {
Dbg("Successfully mounted filesystem.");
controller.SendOk();
}
else {
Dbg("Failed to mount filesystem.");
controller.SendRequestFailed(error);
}
controllers.Add(controller);
break;
}
case controller.Unmount(char[]! in ExHeap expath) in controllers:
{
string! path = Bitter.ToString2(expath);
delete expath;
ErrorCode error = Unmount(path);
if (error == ErrorCode.NoError) {
controller.SendOk();
}
else {
controller.SendRequestFailed(error);
}
Dbg("Received request to unmount '{0}'.");
controllers.Add(controller);
break;
}
case controller.ChannelClosed() in controllers:
Dbg("A controller client has disconnected.");
delete controller;
break;
}
}
}
}
Iso9660Fs FindFileSystemByMountPath(string! mountPath)
{
foreach (Iso9660Fs! fs in filesystems) {
if (fs.MountPath == mountPath) {
return fs;
}
}
return null;
}
ErrorCode Unmount(string! mountPath)
{
Iso9660Fs fs = FindFileSystemByMountPath(mountPath);
if (fs == null) {
Dbg("Cannot unmount filesystem at '{0}'; no such filesystem.", mountPath);
return ErrorCode.NotFound;
}
if (path != mountPath) {
Dbg("We are not mounted at that location. Rejecting request.");
controller.SendRequestFailed(ErrorCode.NotFound);
controllers.Add(controller);
break;
}
Shutdown();
Dbg("Filesystem dismounted.");
mounted = false;
controller.SendOk();
}
ErrorCode ProcessMountRequest(string! device, string! location)
{
expose(this)
{
if (mounted) {
Dbg("This service cannot yet handle more than one volume concurrently.");
return ErrorCode.NotSupported;
}
long unit = Iso9660.Stdio.RawDevice.LoadDisk(device);
if (unit < 0) {
Dbg("LoadDisk failed with unit = " + unit);
return ErrorCode.Unknown;
}
Dbg("Successfully loaded disk '{0}'.", device);
Dbg("Reading root...");
byte[] superBlock = new byte[2048];
Iso9660.Stdio.RawDevice.ReadBlock(superBlock,16);
// 0x01 + "CD001"
if (superBlock[0] != (byte)0x01 ||
superBlock[1] != (byte)0x43 ||
superBlock[2] != (byte)0x44 ||
superBlock[3] != (byte)0x30 ||
superBlock[4] != (byte)0x30 ||
superBlock[5] != (byte)0x31)
{
Dbg("The filesystem does not contain a valid ISO9660 signature of 'CD001'. Rejecting mount request.");
return ErrorCode.Unknown;
}
//
// 1. check media & show label
//
ushort set = ByteArray.ToUshort(superBlock, SuperBlock.SET_SIZE);
ushort seq = ByteArray.ToUshort(superBlock, SuperBlock.SEQ_NO);
ushort blk = ByteArray.ToUshort(superBlock, SuperBlock.BLK_SIZE);
if (set != 1 || seq != 1 || blk != 2048) {
Dbg("The disk does not contain a valid ISO9660 superblock.");
if (set != 1)
Dbg(" The set size is {0}; expected 1.", set);
if (seq != 1)
Dbg(" The seq size is {0}; expected 1.", seq);
if (blk != 1)
Dbg(" The block size is {0}; expected 2048.", blk);
return ErrorCode.Unknown;
}
string label = ByteArray.ToString(superBlock, SuperBlock.LABEL, 32);
//
// 2. "unmarshall" & init root
//
Iso9660DirectoryInfo root = new Iso9660DirectoryInfo();
root.InitializeMe(superBlock, SuperBlock.ROOT_DIR);
root.myPrefix = "";
Dbg("Superblock looks ok.");
Dbg("Label: '{0}'.", label);
SuperBlock.root = root;
mountPath = location;
Dbg("Starting file instance worker...");
FSFileInstanceWorker.Start();
Dbg("Starting directory instance worker...");
bool result = FSDirectoryInstanceWorker.Start(location);
if (!result) {
Dbg("The directory instance worker failed to initialize.");
Shutdown();
return ErrorCode.Unknown;
}
Dbg("done.");
mounted = true;
return ErrorCode.NoError;
}
}
void Shutdown()
{
Dbg("Terminating directory instance worker...");
FSDirectoryInstanceWorker.Terminate();
Dbg("done.");
Dbg("Terminating file instance worker...");
FSFileInstanceWorker.Terminate();
Dbg("done.");
}
void ITracked.Expose() {}
void ITracked.UnExpose() {}
void ITracked.Acquire() {}
void ITracked.Release() {}
}
class Iso9660Fs
{
public string! MountPath;
public string! DevicePath;
public Process! Process;
public bool IsControlEndpointReady;
public TRef<FileSystemControlContract.Imp> ControlEndpointRef;
}
}