1534 lines
64 KiB
Plaintext
1534 lines
64 KiB
Plaintext
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: SdsUtils.sg
|
|
//
|
|
// Note:
|
|
//
|
|
|
|
using System;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Collections;
|
|
|
|
using Microsoft.Singularity;
|
|
using Microsoft.Singularity.Directory;
|
|
using Microsoft.Singularity.Channels;
|
|
using Microsoft.Singularity.V1.Services;
|
|
using Microsoft.SingSharp;
|
|
|
|
namespace Microsoft.Singularity.Directory
|
|
{
|
|
public class SdsUtils
|
|
{
|
|
public static string! NodeTypeToString(NodeType n)
|
|
{
|
|
string s;
|
|
switch (n) {
|
|
case NodeType.Directory :
|
|
s = "Directory";
|
|
break;
|
|
case NodeType.File :
|
|
s = "File";
|
|
break;
|
|
case NodeType.IoMemory :
|
|
s = "IoMemory";
|
|
break;
|
|
case NodeType.ServiceProvider :
|
|
s = "ServiceProvider";
|
|
break;
|
|
case NodeType.SymLink :
|
|
s = "SymLink";
|
|
break;
|
|
case NodeType.BadNode :
|
|
s = "BadNode";
|
|
break;
|
|
default:
|
|
s = "Impossible!";
|
|
break;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
public static string! ErrorCodeToString(ErrorCode code)
|
|
{
|
|
string s;
|
|
switch (code) {
|
|
case ErrorCode.NoError :
|
|
s = "NoError";
|
|
break;
|
|
case ErrorCode.AccessDenied :
|
|
s = "AccessDenied";
|
|
break;
|
|
case ErrorCode.AlreadyExists :
|
|
s = "AlreadyExists";
|
|
break;
|
|
case ErrorCode.BadArguments:
|
|
s = "BadArguments";
|
|
break;
|
|
case ErrorCode.ContractNotSupported :
|
|
s = "ContractNotSupported";
|
|
break;
|
|
case ErrorCode.DirectoryNotEmpty :
|
|
s = "DirectoryNotEmpty";
|
|
break;
|
|
case ErrorCode.NotFound :
|
|
s = "NotFound";
|
|
break;
|
|
case ErrorCode.ChannelClosed :
|
|
s = "ChannelClosed";
|
|
break;
|
|
case ErrorCode.Unsatisfiable :
|
|
s = "Unsatisfiable";
|
|
break;
|
|
case ErrorCode.NotImplemented :
|
|
s = "NotImplemented";
|
|
break;
|
|
case ErrorCode.NotSupported :
|
|
s = "NotSupported";
|
|
break;
|
|
case ErrorCode.CapacityReached :
|
|
s = "CapacityReached";
|
|
break;
|
|
case ErrorCode.InsufficientResources :
|
|
s = "InsufficientResources";
|
|
break;
|
|
case ErrorCode.DirectoryFull :
|
|
s = "DirectoryFull";
|
|
break;
|
|
case ErrorCode.NotDirectory :
|
|
s = "NotDirectory";
|
|
break;
|
|
case ErrorCode.NotLink :
|
|
s = "NotLink";
|
|
break;
|
|
case ErrorCode.NotProvider :
|
|
s = "NotProvider";
|
|
break;
|
|
case ErrorCode.NotFile :
|
|
s = "NotFile";
|
|
break;
|
|
case ErrorCode.IsOpen:
|
|
s = "IsOpen";
|
|
break;
|
|
case ErrorCode.Unknown :
|
|
s = "Unknown";
|
|
break;
|
|
default:
|
|
s = "Impossible!";
|
|
break;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// DSP cache
|
|
//------------------------------------------------------------------------------
|
|
|
|
static SortedList! dspCache = new SortedList();
|
|
static int cacheUsers = 0; // serves as counting semaphore
|
|
static bool cacheShutdown = false;
|
|
static readonly Mutex! cacheEmpty = new Mutex();
|
|
static bool flushCacheWaiting = false;
|
|
|
|
//
|
|
// Atomically:
|
|
// - Checks the cache for the specified DSP, and returns it if present.
|
|
// - If not present, binds a new channel to the DSP and puts a TRef
|
|
// for it in the cache, but .Acquires() the contents and returns them.
|
|
//
|
|
// Regardless, call ReleaseCachedDSP() to return the channel to the cache
|
|
// when done!
|
|
//
|
|
// The "ds" argument provides a DirectoryServiceContract through which to
|
|
// bind to the requested service, if a cached channel is not available.
|
|
//
|
|
// Returns null if anything goes wrong, in which case errorOut is set
|
|
//
|
|
// This is public so that sdsutilsacl.sg can use it
|
|
public static DirectoryServiceContract.Imp GetDSPChannel(DirectoryServiceContract.Imp:Ready! ds,
|
|
string! prefix, out ErrorCode errorOut)
|
|
{
|
|
errorOut = ErrorCode.NoError;
|
|
TRef<DirectoryServiceContract.Imp:Ready> wrapper;
|
|
|
|
lock (dspCache) {
|
|
if (!cacheShutdown){
|
|
object o = dspCache[prefix];
|
|
|
|
if (o != null) {
|
|
//DebugStub.WriteLine("dspCache: {0} found in cache", __arglist (prefix));
|
|
wrapper = (TRef<DirectoryServiceContract.Imp:Ready>)o;
|
|
}
|
|
else {
|
|
// No cached channel found; create and bind one
|
|
//DebugStub.WriteLine("dspCache: {0} not found in cache; creating", __arglist(prefix));
|
|
DirectoryServiceContract.Imp! dsImp;
|
|
DirectoryServiceContract.Exp! dsExp;
|
|
DirectoryServiceContract.NewChannel(out dsImp, out dsExp);
|
|
bool bound = BindDSP(prefix, ds, dsExp, out errorOut);
|
|
|
|
if (!bound) {
|
|
delete dsImp;
|
|
return null; // failure path;
|
|
}
|
|
else {
|
|
dsImp.RecvSuccess();
|
|
}
|
|
// This is internal so that sdsutilsacl.sg can use it
|
|
|
|
// Put a placeholder TRef into the cache to signal to other threads
|
|
// that this channel exists
|
|
wrapper = new TRef<DirectoryServiceContract.Imp:Ready>(dsImp);
|
|
dspCache.Add(prefix, wrapper);
|
|
}
|
|
cacheUsers++;
|
|
}
|
|
else {
|
|
wrapper = null;
|
|
}
|
|
|
|
} //lock
|
|
|
|
// Must Acquire() outside the lock{} construct lest we deadlock!
|
|
if (!cacheShutdown) {
|
|
assume(wrapper != null);
|
|
return wrapper.Acquire();
|
|
}
|
|
else return null;
|
|
}
|
|
|
|
// This is public so that sdsutilsacl.sg can use it
|
|
public static void ReleaseDSPChannel(string! prefix, [Claims] DirectoryServiceContract.Imp:Ready! dsp)
|
|
{
|
|
lock (dspCache) {
|
|
object o = dspCache[prefix];
|
|
|
|
if (o == null) {
|
|
// Shouldn't happen; the caller is trying to release a channel back into the
|
|
// cache that was not acquired via GetDSPChannel.
|
|
assert false;
|
|
}
|
|
else {
|
|
((TRef<DirectoryServiceContract.Imp:Ready>)o).Release(dsp);
|
|
}
|
|
if (--cacheUsers == 0) {
|
|
// the cache is empty is there anyone we need to inform?
|
|
if (flushCacheWaiting) {
|
|
cacheEmpty.ReleaseMutex();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void FlushCache()
|
|
{
|
|
lock (dspCache) {
|
|
cacheShutdown = true;
|
|
if (cacheUsers == 0) {
|
|
}
|
|
else {
|
|
flushCacheWaiting = true;
|
|
}
|
|
}
|
|
if (flushCacheWaiting){
|
|
cacheEmpty.WaitOne();
|
|
}
|
|
|
|
foreach (TRef<DirectoryServiceContract.Imp:Ready>! wrapper in dspCache) {
|
|
DirectoryServiceContract.Imp x = wrapper.Acquire();
|
|
delete x;
|
|
}
|
|
dspCache.Clear();
|
|
}
|
|
|
|
// find the longest matching path prefix in the dspCache
|
|
// if one is found start return the endpoint, prefix and remaining path
|
|
// The function is linear. Perf will not be a problem as there will be
|
|
// few entries (< 10) =
|
|
|
|
// TODO should have wrapper to all the functions below that call
|
|
// that call this function 1st like Bind/BindEx does
|
|
|
|
public static DirectoryServiceContract.Imp:Ready FindMaximalPreBoundDsp(
|
|
string! path,
|
|
DirectoryServiceContract.Imp:Ready! ds,
|
|
out string! prefix,
|
|
out string! remainder)
|
|
{
|
|
string pre = "";
|
|
int longestLength = 0;
|
|
bool matchFound = false;
|
|
|
|
lock (dspCache) {
|
|
// look for the longest match in the cache
|
|
for (int i=0; i < dspCache.Count; i++) {
|
|
string s = (string) dspCache.GetKey(i);
|
|
if (s != null && s.Length > longestLength) {
|
|
string foo = path.Substring(0,Math.Min(path.Length, s.Length));
|
|
if (s == foo) {
|
|
pre = s;
|
|
remainder = path.Substring(Math.Min(path.Length, s.Length));
|
|
longestLength = s.Length;
|
|
matchFound = true;
|
|
}
|
|
}
|
|
}
|
|
} //lock
|
|
|
|
if (matchFound) {
|
|
ErrorCode errorOut;
|
|
prefix = pre;
|
|
remainder = path.Substring(pre.Length);
|
|
DirectoryServiceContract.Imp dsp = GetDSPChannel(ds, pre, out errorOut);
|
|
assert (dsp != null);
|
|
return dsp;
|
|
}
|
|
else {
|
|
prefix = "";
|
|
remainder = path;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// BindDSP
|
|
//------------------------------------------------------------------------------
|
|
|
|
public static bool BindDSP(string! path, DirectoryServiceContract.Imp:Start! ds, [Claims] ServiceContract.Exp! exp, out ErrorCode errorOut)
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
exPath = Bitter.FromString2(path);
|
|
|
|
ds.SendBind(exPath,exp);
|
|
switch receive
|
|
{
|
|
case ds.NakBind(rejected, error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
delete rejected;
|
|
return false;
|
|
|
|
case ds.AckBind():
|
|
// Success
|
|
errorOut = ErrorCode.NoError;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
//DebugStub.Break();
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakBindReparse(i_prefix,i_suffix,linkFound, rejected):
|
|
DebugStub.Break();
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
delete rejected;
|
|
errorOut = ErrorCode.Unknown;
|
|
return false;
|
|
break;
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
// Bind: checks for a prefix match before calling the regular bind
|
|
//------------------------------------------------------------------------------
|
|
#if DOES_NOT_WORK
|
|
public static bool Bind(string! path, DirectoryServiceContract.Imp:Ready! ds,
|
|
[Claims] ServiceContract.Exp! exp, out ErrorCode errorOut)
|
|
{
|
|
string! remainder;
|
|
string! prefix;
|
|
|
|
// see if we can short-circuit a whole bunch of work
|
|
DirectoryServiceContract.Imp:Ready cachedDsp =
|
|
FindMaximalPreBoundDsp(path, ds, out prefix, out remainder);
|
|
if (cachedDsp == null) {
|
|
return BindEx(path,ds,exp, out errorOut);
|
|
}
|
|
else {
|
|
bool ok = BindEx(remainder,cachedDsp,exp, out errorOut);
|
|
ReleaseDSPChannel(prefix, cachedDsp);
|
|
return ok;
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
// BindEx
|
|
//------------------------------------------------------------------------------
|
|
|
|
public static bool BindEx(string! path, DirectoryServiceContract.Imp:Ready! ds,
|
|
[Claims] ServiceContract.Exp! exp, out ErrorCode errorOut)
|
|
#else
|
|
public static bool Bind(string! path, DirectoryServiceContract.Imp:Ready! ds,
|
|
[Claims] ServiceContract.Exp! exp, out ErrorCode errorOut)
|
|
#endif
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
exPath = Bitter.FromString2(path);
|
|
|
|
ds.SendBind(exPath,exp);
|
|
switch receive
|
|
{
|
|
case ds.NakBind(rejected, error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
delete rejected;
|
|
return false;
|
|
|
|
case ds.AckBind():
|
|
// Success
|
|
errorOut = ErrorCode.NoError;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
//DebugStub.Break();
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakBindReparse(i_prefix, i_suffix, linkFound, rejected):
|
|
// traversed either a mount point or a link
|
|
string pre = Bitter.ToString2(i_prefix);
|
|
string suf = Bitter.ToString(i_suffix);
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
|
|
#if DEBUG_X
|
|
DebugStub.WriteLine("bind reparse: pre={0}, suf={1}, linkfound ={2}",
|
|
__arglist(pre,suf, linkFound? "true": "false"));
|
|
#endif
|
|
|
|
// Either a SymLink or a non-leaf provider node has been encountered.
|
|
if (linkFound) {
|
|
//reissue search
|
|
// DebugStub.WriteLine("link: issuing rebind to '{0}'",__arglist(pre));
|
|
return Bind(pre, ds, rejected, out errorOut);;
|
|
}
|
|
else {
|
|
// Bind to the prefix ServiceProvider and continue search
|
|
DirectoryServiceContract.Imp dsImp = GetDSPChannel(ds, pre, out errorOut);
|
|
|
|
if (dsImp == null) {
|
|
delete rejected;
|
|
return false; // failure; code already in errorOut
|
|
}
|
|
|
|
try {
|
|
if ( null == suf) {
|
|
// Strange to get a NakBindReparse with no suffix
|
|
delete rejected;
|
|
errorOut = ErrorCode.NotFound;
|
|
return false;
|
|
}
|
|
else {
|
|
// There is a trailing part still to bind
|
|
return Bind(suf, dsImp, rejected, out errorOut);
|
|
}
|
|
}
|
|
finally {
|
|
ReleaseDSPChannel(pre, dsImp);
|
|
}
|
|
} //!linkFound
|
|
break;
|
|
} //switch
|
|
} //Bind
|
|
|
|
//------------------------------------------------------------------------------
|
|
// CreateFile
|
|
//------------------------------------------------------------------------------
|
|
public static bool CreateFile (string! path,
|
|
DirectoryServiceContract.Imp:Start! ds,
|
|
out ErrorCode errorOut )
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
exPath = Bitter.FromString2(path);
|
|
bool results;
|
|
|
|
|
|
ds.SendCreateFile(exPath);
|
|
switch receive
|
|
{
|
|
case ds.NakCreateFile(error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
return false;
|
|
|
|
case ds.AckCreateFile():
|
|
// Success
|
|
errorOut = ErrorCode.NoError;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakCreateFileReparse(i_prefix,
|
|
i_suffix,
|
|
linkFound) :
|
|
// traversed either a mount point or a link
|
|
string pre= Bitter.ToString2(i_prefix);
|
|
string suf= Bitter.ToString(i_suffix);
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
|
|
DebugStub.WriteLine("CreateFile.reparse: pre={0}, suf={1}, linkfound ={2}",
|
|
__arglist(pre,suf, linkFound? "true": "false"));
|
|
|
|
// Either a SymLink or a non-leaf provider node has been encountered.
|
|
if (linkFound) {
|
|
//reissue search
|
|
DebugStub.WriteLine("link: issuing rebind to{0}",__arglist(pre));
|
|
return CreateFile(pre, ds, out errorOut);
|
|
}
|
|
else {
|
|
// Bind to the ServiceProvider and continue search
|
|
DirectoryServiceContract.Imp dsImp = GetDSPChannel(ds, pre, out errorOut);
|
|
//DebugStub.WriteLine("sds create suf={0}", __arglist(suf));
|
|
if (dsImp == null) {
|
|
return false; // failure; code already in errorOut
|
|
}
|
|
|
|
try {
|
|
if ( null == suf) {
|
|
// Strange to get a NakCreateFileReparse here
|
|
errorOut = ErrorCode.Unknown;
|
|
return false;
|
|
}
|
|
else {
|
|
return CreateFile(suf, dsImp, out errorOut);
|
|
}
|
|
}
|
|
finally {
|
|
ReleaseDSPChannel(pre, dsImp);
|
|
}
|
|
break;
|
|
} //!linkFound
|
|
break;
|
|
} //switch
|
|
} //CreateFile
|
|
|
|
//------------------------------------------------------------------------------
|
|
// CreateDirectory
|
|
//------------------------------------------------------------------------------
|
|
public static bool CreateDirectory (string! path,
|
|
DirectoryServiceContract.Imp:Ready! ds,
|
|
out ErrorCode errorOut )
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
exPath = Bitter.FromString2(path);
|
|
bool results;
|
|
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
ds.SendCreateDirectory(exPath);
|
|
try {
|
|
switch receive
|
|
{
|
|
case ds.NakCreateDirectory(error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
return false;
|
|
|
|
case ds.AckCreateDirectory():
|
|
// Success
|
|
errorOut = ErrorCode.NoError;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakCreateDirectoryReparse(i_prefix,
|
|
i_suffix,
|
|
linkFound) :
|
|
// traversed either a mount point or a link
|
|
string pre= Bitter.ToString2(i_prefix);
|
|
string suf= Bitter.ToString(i_suffix);
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
|
|
DebugStub.WriteLine("CreateDirectory.reparse: pre={0}, suf={1}, linkfound ={2}",
|
|
__arglist(pre,suf, linkFound? "true": "false"));
|
|
|
|
// Either a SymLink or a non-leaf provider node has been encountered.
|
|
if (linkFound) {
|
|
//reissue search
|
|
DebugStub.WriteLine("link: issuing rebind to{0}",__arglist(pre));
|
|
return CreateDirectory(pre, ds, out errorOut);
|
|
}
|
|
else {
|
|
// Bind to the ServiceProvider and continue search
|
|
DirectoryServiceContract.Imp dsImp = GetDSPChannel(ds, pre, out errorOut);
|
|
|
|
if (dsImp == null) {
|
|
return false; // failure; code already in errorOut
|
|
}
|
|
|
|
try {
|
|
if ( null == suf) {
|
|
// Strange to get a NakCreateDirectoryReparse here!
|
|
errorOut = ErrorCode.Unknown;
|
|
return false;
|
|
}
|
|
else {
|
|
return CreateDirectory(suf, dsImp, out errorOut);
|
|
}
|
|
}
|
|
finally {
|
|
ReleaseDSPChannel(pre, dsImp);
|
|
}
|
|
} //!linkFound
|
|
break;
|
|
} //switch
|
|
}
|
|
finally {
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
}
|
|
} //CreateDirectory
|
|
|
|
//------------------------------------------------------------------------------
|
|
// CreateLink
|
|
//------------------------------------------------------------------------------
|
|
public static bool CreateLink (string! path,
|
|
string! value,
|
|
DirectoryServiceContract.Imp:Ready! ds,
|
|
out ErrorCode errorOut )
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
char[]! in ExHeap exValue;
|
|
exPath = Bitter.FromString2(path);
|
|
exValue = Bitter.FromString2(value);
|
|
bool results;
|
|
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
ds.SendCreateLink(exPath,exValue);
|
|
try {
|
|
switch receive
|
|
{
|
|
case ds.NakCreateLink(error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
return false;
|
|
|
|
case ds.AckCreateLink():
|
|
// Success
|
|
errorOut = ErrorCode.NoError;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakCreateLinkReparse(i_prefix,
|
|
i_suffix,
|
|
linkFound) :
|
|
// traversed either a mount point or a link
|
|
string pre= Bitter.ToString2(i_prefix);
|
|
string suf= Bitter.ToString(i_suffix);
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
|
|
DebugStub.WriteLine("CreateLink.reparse: pre={0}, suf={1}, linkfound ={2}",
|
|
__arglist(pre,suf, linkFound? "true": "false"));
|
|
|
|
// Either a SymLink or a non-leaf provider node has been encountered.
|
|
if (linkFound) {
|
|
//reissue search
|
|
DebugStub.WriteLine("link: issuing rebind to{0}",__arglist(pre));
|
|
results = CreateLink(pre, value, ds, out errorOut);
|
|
return results;
|
|
}
|
|
else {
|
|
// Bind to the ServiceProvider and continue search
|
|
DirectoryServiceContract.Imp dsImp = GetDSPChannel(ds, pre, out errorOut);
|
|
|
|
if (dsImp == null) {
|
|
return false; // failure; code already in errorOut
|
|
}
|
|
|
|
try {
|
|
if ( null == suf) {
|
|
// Strange to get a NakCreateLinkReparse here!
|
|
errorOut = ErrorCode.Unknown;
|
|
return false;
|
|
}
|
|
else {
|
|
return CreateLink(suf,value, dsImp, out errorOut);
|
|
}
|
|
}
|
|
finally {
|
|
ReleaseDSPChannel(pre, dsImp);
|
|
}
|
|
} //!linkFound
|
|
break;
|
|
} //switch
|
|
}
|
|
finally {
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
}
|
|
} //CreateLink
|
|
|
|
//------------------------------------------------------------------------------
|
|
// DeleteFile
|
|
//------------------------------------------------------------------------------
|
|
public static bool DeleteFile(string! path,
|
|
DirectoryServiceContract.Imp:Ready! ds,
|
|
out ErrorCode errorOut )
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
exPath = Bitter.FromString2(path);
|
|
bool results;
|
|
DebugStub.WriteLine("sds deletefile path={0}", __arglist(path));
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
ds.SendDeleteFile(exPath);
|
|
try {
|
|
switch receive
|
|
{
|
|
case ds.NakDeleteFile(error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
DebugStub.WriteLine("sds delete file fails {0}", __arglist(error));
|
|
errorOut = error;
|
|
return false;
|
|
|
|
case ds.AckDeleteFile():
|
|
// Success
|
|
errorOut = ErrorCode.NoError;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakDeleteFileReparse(i_prefix,
|
|
i_suffix,
|
|
linkFound) :
|
|
// traversed either a mount point or a link
|
|
string pre= Bitter.ToString2(i_prefix);
|
|
string suf= Bitter.ToString(i_suffix);
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
|
|
DebugStub.WriteLine("DeleteFile.reparse: pre={0}, suf={1}, linkfound ={2}",
|
|
__arglist(pre,suf, linkFound? "true": "false"));
|
|
|
|
// Either a SymLink or a non-leaf provider node has been encountered.
|
|
if (linkFound) {
|
|
//reissue search
|
|
DebugStub.WriteLine("link: issuing rebind to{0}",__arglist(pre));
|
|
results = DeleteFile(pre, ds, out errorOut);
|
|
return results;
|
|
}
|
|
else {
|
|
// Bind to the ServiceProvider and continue search
|
|
DirectoryServiceContract.Imp dsImp = GetDSPChannel(ds, pre, out errorOut);
|
|
|
|
if (dsImp == null) {
|
|
return false; // failure; code already in errorOut
|
|
}
|
|
DebugStub.WriteLine("sds deletefile: got dsp @ {0}. continuing", __arglist(pre));
|
|
|
|
try {
|
|
if ( null == suf) {
|
|
// Strange to get a NakDeleteFileReparse here!
|
|
errorOut = ErrorCode.Unknown;
|
|
return false;
|
|
}
|
|
else {
|
|
DebugStub.WriteLine("sds deletefile: continuing with {0}", __arglist(suf));
|
|
return DeleteFile(suf, dsImp, out errorOut);
|
|
}
|
|
}
|
|
finally {
|
|
ReleaseDSPChannel(pre, dsImp);
|
|
}
|
|
} //!linkFound
|
|
break;
|
|
} //switch
|
|
}
|
|
finally {
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
}
|
|
} //DeleteFile
|
|
|
|
//------------------------------------------------------------------------------
|
|
// DeleteLink
|
|
//------------------------------------------------------------------------------
|
|
public static bool DeleteLink (string! path,
|
|
DirectoryServiceContract.Imp:Ready! ds,
|
|
out ErrorCode errorOut )
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
exPath = Bitter.FromString2(path);
|
|
bool results;
|
|
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
ds.SendDeleteLink(exPath);
|
|
try {
|
|
switch receive
|
|
{
|
|
case ds.NakDeleteLink(error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
return false;
|
|
|
|
case ds.AckDeleteLink():
|
|
// Success
|
|
errorOut = ErrorCode.NoError;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakDeleteLinkReparse(i_prefix,
|
|
i_suffix,
|
|
linkFound) :
|
|
// traversed either a mount point or a link
|
|
string pre= Bitter.ToString2(i_prefix);
|
|
string suf= Bitter.ToString(i_suffix);
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
|
|
DebugStub.WriteLine("DeleteLink.reparse: pre={0}, suf={1}, linkfound ={2}",
|
|
__arglist(pre,suf, linkFound? "true": "false"));
|
|
|
|
// Either a SymLink or a non-leaf provider node has been encountered.
|
|
if (linkFound) {
|
|
//reissue search
|
|
DebugStub.WriteLine("link: issuing rebind to{0}",__arglist(pre));
|
|
results = DeleteLink(pre, ds, out errorOut);
|
|
return results;
|
|
}
|
|
else {
|
|
// Bind to the ServiceProvider and continue search
|
|
DirectoryServiceContract.Imp dsImp = GetDSPChannel(ds, pre, out errorOut);
|
|
|
|
if (dsImp == null) {
|
|
return false; // failure; code already in errorOut
|
|
}
|
|
|
|
try {
|
|
if ( null == suf) {
|
|
// Strange to get a NakDeleteLinkReparse here!
|
|
errorOut = ErrorCode.Unknown;
|
|
return false;
|
|
}
|
|
else {
|
|
return DeleteLink(suf, dsImp, out errorOut);
|
|
}
|
|
}
|
|
finally {
|
|
ReleaseDSPChannel(pre, dsImp);
|
|
}
|
|
} //!linkFound
|
|
break;
|
|
} //switch
|
|
}
|
|
finally {
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
}
|
|
} //DeleteLink
|
|
|
|
//------------------------------------------------------------------------------
|
|
// GetLinkValue
|
|
//------------------------------------------------------------------------------
|
|
public static bool GetLinkValue (string! path,
|
|
DirectoryServiceContract.Imp:Ready! ds,
|
|
out string linkValue,
|
|
out ErrorCode errorOut )
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
exPath = Bitter.FromString2(path);
|
|
bool results;
|
|
linkValue = null;
|
|
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
ds.SendGetLinkValue(exPath);
|
|
try {
|
|
switch receive
|
|
{
|
|
case ds.NakGetLinkValue(error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
return false;
|
|
|
|
case ds.AckGetLinkValue(i_value):
|
|
// Success
|
|
linkValue = Bitter.ToString2(i_value);
|
|
delete i_value;
|
|
errorOut = ErrorCode.NoError;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakGetLinkValueReparse(i_prefix,
|
|
i_suffix,
|
|
linkFound) :
|
|
// traversed either a mount point or a link
|
|
string pre= Bitter.ToString2(i_prefix);
|
|
string suf= Bitter.ToString(i_suffix);
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
|
|
DebugStub.WriteLine("GetLinkValue.reparse: pre={0}, suf={1}, linkfound ={2}",
|
|
__arglist(pre,suf, linkFound? "true": "false"));
|
|
|
|
// Either a SymLink or a non-leaf provider node has been encountered.
|
|
if (linkFound) {
|
|
//reissue search
|
|
DebugStub.WriteLine("link: issuing rebind to{0}",__arglist(pre));
|
|
results = GetLinkValue(pre, ds, out linkValue, out errorOut);
|
|
return results;
|
|
}
|
|
else {
|
|
// Bind to the ServiceProvider and continue search
|
|
DirectoryServiceContract.Imp dsImp = GetDSPChannel(ds, pre, out errorOut);
|
|
|
|
if (dsImp == null) {
|
|
return false; // failure; code already in errorOut
|
|
}
|
|
|
|
try {
|
|
if ( null == suf) {
|
|
// Strange to get a NakGetLinkValueReparse here!
|
|
errorOut = ErrorCode.Unknown;
|
|
return false;
|
|
}
|
|
else {
|
|
return GetLinkValue(suf, dsImp, out linkValue, out errorOut);
|
|
}
|
|
}
|
|
finally {
|
|
ReleaseDSPChannel(pre, dsImp);
|
|
}
|
|
} //!linkFound
|
|
break;
|
|
} //switch
|
|
}
|
|
finally {
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
}
|
|
} //GetLinkValue
|
|
|
|
//------------------------------------------------------------------------------
|
|
// DeleteDirectory
|
|
//------------------------------------------------------------------------------
|
|
public static bool DeleteDirectory (string! path,
|
|
DirectoryServiceContract.Imp:Ready! ds,
|
|
out ErrorCode errorOut )
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
exPath = Bitter.FromString2(path);
|
|
bool results;
|
|
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
ds.SendDeleteDirectory(exPath);
|
|
try {
|
|
switch receive
|
|
{
|
|
case ds.NakDeleteDirectory(error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
return false;
|
|
|
|
case ds.AckDeleteDirectory():
|
|
// Success
|
|
errorOut = ErrorCode.NoError;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakDeleteDirectoryReparse(i_prefix,
|
|
i_suffix,
|
|
linkFound) :
|
|
// traversed either a mount point or a link
|
|
string pre= Bitter.ToString2(i_prefix);
|
|
string suf= Bitter.ToString(i_suffix);
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
|
|
DebugStub.WriteLine("DeleteDirectory.reparse: pre={0}, suf={1}, linkfound ={2}",
|
|
__arglist(pre,suf, linkFound? "true": "false"));
|
|
|
|
//DebugStub.Break();
|
|
// Either a SymLink or a non-leaf provider node has been encountered.
|
|
if (linkFound) {
|
|
//reissue search
|
|
DebugStub.WriteLine("link: issuing rebind to{0}",__arglist(pre));
|
|
results = DeleteDirectory(pre, ds, out errorOut);
|
|
return results;
|
|
}
|
|
else {
|
|
// Bind to the ServiceProvider and continue search
|
|
DirectoryServiceContract.Imp dsImp = GetDSPChannel(ds, pre, out errorOut);
|
|
|
|
if (dsImp == null) {
|
|
//DebugStub.Break();
|
|
return false; // failure; code already in errorOut
|
|
}
|
|
|
|
try {
|
|
if ( null == suf) {
|
|
// Strange to get a NakDeleteDirectoryReparse here!
|
|
errorOut = ErrorCode.Unknown;
|
|
return false;
|
|
}
|
|
else {
|
|
return DeleteDirectory(suf, dsImp, out errorOut);
|
|
}
|
|
}
|
|
finally {
|
|
ReleaseDSPChannel(pre, dsImp);
|
|
}
|
|
} //!linkFound
|
|
break;
|
|
} //switch
|
|
}
|
|
finally {
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
}
|
|
} //DeleteDirectory
|
|
|
|
public static bool IsMatch(string! name, string! pattern)
|
|
{
|
|
bool match = false;
|
|
bool continueMatch = true;
|
|
string prefix = null;
|
|
string postfix = null;
|
|
|
|
int starPos = pattern.IndexOf("*");
|
|
|
|
if (starPos != -1) {
|
|
if (starPos == 0) {
|
|
prefix = null;
|
|
postfix = pattern.Substring(1);
|
|
}
|
|
else if (starPos == pattern.Length-1) {
|
|
prefix = pattern.Substring(0, pattern.Length-1);
|
|
postfix = null;
|
|
}
|
|
else {
|
|
prefix = pattern.Substring(0, starPos);
|
|
postfix = pattern.Substring(starPos+1);
|
|
}
|
|
|
|
if (prefix != null) {
|
|
if (!name.StartsWith(prefix))
|
|
continueMatch = false;
|
|
}
|
|
if (continueMatch && postfix != null) {
|
|
if (!name.EndsWith(postfix)) {
|
|
continueMatch = false;
|
|
}
|
|
}
|
|
match = continueMatch;
|
|
}
|
|
else if (pattern == name) {
|
|
match = true;
|
|
}
|
|
|
|
//DebugStub.Print("name={0} pre={1} post={2} match={3}\n",
|
|
// __arglist(name, prefix, postfix, match));
|
|
return match;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Concatenate 2 sets of ExHeap EnumerationRecords
|
|
//------------------------------------------------------------------------------
|
|
private static EnumerationRecords[]! in ExHeap Concat(
|
|
[Claims] EnumerationRecords[]! in ExHeap rec1,
|
|
[Claims] EnumerationRecords[]! in ExHeap rec2
|
|
)
|
|
{
|
|
int size = rec1.Length + rec2.Length;
|
|
EnumerationRecords [] in ExHeap records =
|
|
new [ExHeap] EnumerationRecords[size];
|
|
|
|
// copy both rec1 and rec2 into records
|
|
|
|
for (int i = 0; i < rec1.Length; i++) {
|
|
expose (records[i]) {
|
|
expose (rec1[i]) {
|
|
delete records[i].Path;
|
|
records[i].Path = (!)rec1[i].Path;
|
|
//allocate a byte to satisfy checker
|
|
rec1[i].Path = new [ExHeap] char [1];
|
|
records[i].Type = rec1[i].Type;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0, j = rec1.Length ; i < rec2.Length; i++, j++) {
|
|
expose (records[j]) {
|
|
expose (rec2[i]) {
|
|
delete records[j].Path;
|
|
records[j].Path = (!)rec2[i].Path;
|
|
//allocate a byte to satisfy checker
|
|
rec2[i].Path = new [ExHeap] char [1];
|
|
records[j].Type = rec2[i].Type;
|
|
}
|
|
}
|
|
}
|
|
|
|
delete rec1;
|
|
delete rec2;
|
|
|
|
return records;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
// Find
|
|
//------------------------------------------------------------------------------
|
|
public static EnumerationRecords[] in ExHeap EnumerateDirectory(
|
|
DirectoryServiceContract.Imp:Start! ds,
|
|
out ErrorCode errorOut )
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
EnumerationRecords[] in ExHeap results;
|
|
|
|
ds.SendBeginEnumeration();
|
|
switch receive
|
|
{
|
|
case ds.EnumerationTerminated(error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
return null;
|
|
|
|
case ds.EnumerationEntries(i_results, isMore):
|
|
// Success
|
|
EnumerationRecords[] in ExHeap temp;
|
|
int size = i_results.Length;
|
|
errorOut = ErrorCode.NoError;
|
|
bool doAgain = isMore;
|
|
if (doAgain) {
|
|
while (doAgain) {
|
|
DebugStub.WriteLine(" recvd [{0}], requesting additional enumeration",
|
|
__arglist(size));
|
|
ds.SendReadEnumeration();
|
|
switch receive
|
|
{
|
|
case ds.EnumerationTerminated(error):
|
|
errorOut = error;
|
|
return i_results;
|
|
case ds.EnumerationEntries(i_more_results, isMore2):
|
|
doAgain = isMore2;
|
|
size = i_more_results.Length;
|
|
if (!doAgain){
|
|
i_results = Concat(i_results,i_more_results);
|
|
ds.SendEndEnumeration();
|
|
return i_results;
|
|
break;
|
|
}
|
|
else {
|
|
i_results = Concat(i_results,i_more_results);
|
|
break;
|
|
}
|
|
break;
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
delete i_results;
|
|
return null;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
delete i_results;
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return null;
|
|
break;
|
|
}
|
|
}
|
|
delete i_results;
|
|
return null;
|
|
}
|
|
else {
|
|
// DebugStub.WriteLine(" About to send END enumerate");
|
|
ds.SendEndEnumeration();
|
|
if ( ds.InState(DirectoryServiceContract.EnumerateAck.Value) ) DebugStub.Break();
|
|
if ( !ds.InState(DirectoryServiceContract.Ready.Value) ) DebugStub.Break();
|
|
return i_results;
|
|
}
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return null;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return null;
|
|
break;
|
|
|
|
} //switch
|
|
} //Find
|
|
|
|
//------------------------------------------------------------------------------
|
|
// GetAttributes
|
|
//------------------------------------------------------------------------------
|
|
public static bool GetAttributes (string! path,
|
|
DirectoryServiceContract.Imp:Start! ds,
|
|
out long length,
|
|
out NodeType nodeType,
|
|
out ErrorCode errorOut )
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
exPath = Bitter.FromString2(path);
|
|
bool results;
|
|
|
|
|
|
ds.SendGetAttributes(exPath);
|
|
switch receive
|
|
{
|
|
case ds.NakGetAttributes(error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
length = -1;
|
|
nodeType = NodeType.BadNode;
|
|
return false;
|
|
|
|
case ds.AckGetAttributes(i_nodeType, i_length):
|
|
// Success
|
|
errorOut = ErrorCode.NoError;
|
|
length = i_length;
|
|
nodeType = i_nodeType;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
length = -1;
|
|
nodeType = NodeType.BadNode;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
length = -1;
|
|
nodeType = NodeType.BadNode;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakGetAttributesReparse(i_prefix, i_suffix, linkFound) :
|
|
// traversed either a mount point or a link
|
|
string pre= Bitter.ToString2(i_prefix);
|
|
string suf= Bitter.ToString(i_suffix);
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
|
|
//DebugStub.WriteLine("GetAttributes.reparse: pre={0}, suf={1}, linkfound ={2}",
|
|
// __arglist(pre,suf, linkFound? "true": "false"));
|
|
|
|
// Either a SymLink or a non-leaf provider node has been encountered.
|
|
if (linkFound) {
|
|
//reissue search
|
|
DebugStub.WriteLine("link: issuing rebind to{0}",__arglist(pre));
|
|
results = GetAttributes(pre, ds, out length, out nodeType, out errorOut);
|
|
return results;
|
|
}
|
|
else {
|
|
// Bind to the ServiceProvider and continue search
|
|
DirectoryServiceContract.Imp dsImp = GetDSPChannel(ds, pre, out errorOut);
|
|
|
|
if (dsImp == null) {
|
|
length = -1;
|
|
nodeType = NodeType.BadNode;
|
|
return false; // failure; code already in errorOut
|
|
}
|
|
|
|
try {
|
|
if ( null == suf) {
|
|
// Strange to get a NakGetAttributesReparse here!
|
|
length = -1;
|
|
nodeType = NodeType.BadNode;
|
|
errorOut = ErrorCode.Unknown;
|
|
return false;
|
|
}
|
|
else {
|
|
return GetAttributes(suf, dsImp, out length, out nodeType, out errorOut);
|
|
}
|
|
}
|
|
finally {
|
|
ReleaseDSPChannel(pre, dsImp);
|
|
}
|
|
} //!linkFound
|
|
break;
|
|
} //switch
|
|
} //Find
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Deregister
|
|
//------------------------------------------------------------------------------
|
|
public static bool Deregister (string! path,
|
|
DirectoryServiceContract.Imp:Start! ds,
|
|
out ServiceProviderContract.Imp:Start service,
|
|
out ErrorCode errorOut )
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
exPath = Bitter.FromString2(path);
|
|
bool results;
|
|
service = null;
|
|
|
|
ds.SendDeregister(exPath);
|
|
switch receive
|
|
{
|
|
case ds.NakDeregister( error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
return false;
|
|
|
|
case ds.AckDeregister(ServiceProviderContract.Imp:Start ! i_service):
|
|
// Success
|
|
errorOut = ErrorCode.NoError;
|
|
service = i_service;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakDeregisterReparse(i_prefix,
|
|
i_suffix,
|
|
linkFound) :
|
|
|
|
// traversed either a mount point or a link
|
|
string pre= Bitter.ToString2(i_prefix);
|
|
string suf= Bitter.ToString(i_suffix);
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
|
|
DebugStub.WriteLine("Deregister.reparse: pre={0}, suf={1}, linkfound ={2}",
|
|
__arglist(pre,suf, linkFound? "true": "false"));
|
|
|
|
// Either a SymLink or a non-leaf provider node has been encountered.
|
|
if (linkFound) {
|
|
//reissue search
|
|
DebugStub.WriteLine("link: issuing rebind to{0}",__arglist(pre));
|
|
results = Deregister(pre, ds, out service, out errorOut);
|
|
return results;
|
|
}
|
|
else {
|
|
// Bind to the ServiceProvider and continue search
|
|
DirectoryServiceContract.Imp dsImp = GetDSPChannel(ds, pre, out errorOut);
|
|
|
|
if (dsImp == null) {
|
|
return false; // failure; code already in errorOut
|
|
}
|
|
|
|
try {
|
|
if ( null == suf) {
|
|
// Strange to get a NakDeregisterReparse here!
|
|
errorOut = ErrorCode.Unknown;
|
|
return false;
|
|
}
|
|
else {
|
|
return Deregister(suf, dsImp, out service, out errorOut);
|
|
}
|
|
}
|
|
finally {
|
|
ReleaseDSPChannel(pre, dsImp);
|
|
}
|
|
} //!linkFound
|
|
break;
|
|
} //switch
|
|
} //Deregister
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Register
|
|
//------------------------------------------------------------------------------
|
|
public static bool Register (string! path,
|
|
DirectoryServiceContract.Imp:Start! ds,
|
|
[Claims] ServiceProviderContract.Imp! imp,
|
|
out ErrorCode errorOut )
|
|
{
|
|
errorOut = ErrorCode.Unknown;
|
|
char[]! in ExHeap exPath;
|
|
exPath = Bitter.FromString2(path);
|
|
bool results;
|
|
|
|
ds.SendRegister(exPath,imp);
|
|
switch receive
|
|
{
|
|
case ds.NakRegister(ServiceProviderContract.Imp:Start rejected, error):
|
|
// Failed: no such leaf node, or leaf node is not a file
|
|
errorOut = error;
|
|
delete rejected;
|
|
return false;
|
|
|
|
case ds.AckRegister():
|
|
// Success
|
|
errorOut = ErrorCode.NoError;
|
|
return true;
|
|
break;
|
|
|
|
case ds.ChannelClosed():
|
|
// Directory channel closed unexpectedly
|
|
errorOut = ErrorCode.ChannelClosed;
|
|
return false;
|
|
break;
|
|
|
|
case unsatisfiable :
|
|
// should never happen.
|
|
errorOut = ErrorCode.Unsatisfiable;
|
|
return false;
|
|
break;
|
|
|
|
case ds.NakRegisterReparse(i_prefix,
|
|
i_suffix,
|
|
linkFound,
|
|
ServiceProviderContract.Imp:Start! rejected) :
|
|
// traversed either a mount point or a link
|
|
string pre= Bitter.ToString2(i_prefix);
|
|
string suf= Bitter.ToString(i_suffix);
|
|
delete i_prefix;
|
|
delete i_suffix;
|
|
|
|
DebugStub.WriteLine("Register.reparse: pre={0}, suf={1}, linkfound ={2}",
|
|
__arglist(pre,suf, linkFound? "true": "false"));
|
|
|
|
// Either a SymLink or a non-leaf provider node has been encountered.
|
|
if (linkFound) {
|
|
//reissue search
|
|
DebugStub.WriteLine("link: issuing rebind to{0}",__arglist(pre));
|
|
results = Register(pre, ds, rejected, out errorOut);
|
|
return results;
|
|
}
|
|
else {
|
|
// Bind to the ServiceProvider and continue search
|
|
DirectoryServiceContract.Imp dsImp = GetDSPChannel(ds, pre, out errorOut);
|
|
|
|
if (dsImp == null) {
|
|
delete rejected;
|
|
return false; // failure; code already in errorOut
|
|
}
|
|
|
|
try {
|
|
if ( null == suf) {
|
|
// Strange to get a NakRegisterReparse here!
|
|
delete rejected;
|
|
errorOut = ErrorCode.Unknown;
|
|
return false;
|
|
}
|
|
else {
|
|
return Register(suf, dsImp, rejected, out errorOut);
|
|
}
|
|
}
|
|
finally {
|
|
ReleaseDSPChannel(pre, dsImp);
|
|
}
|
|
} //!linkFound
|
|
break;
|
|
} //switch
|
|
} //Register
|
|
} // class
|
|
}
|