2008-03-05 09:52:00 -05:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Microsoft Research Singularity
|
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
//
|
2008-11-17 18:29:00 -05:00
|
|
|
// Note: First "Atomic" version of the Nameserver. The
|
2008-03-05 09:52:00 -05:00
|
|
|
// atomic blocks have deliberately been made coarse because of
|
|
|
|
// the recursive nature of all functions. The recursive
|
|
|
|
// structure of functions means that the entire function body
|
|
|
|
// becomes a part of an atomic block on a recursive call. This
|
|
|
|
// means that simply "writing" a fine grained looking atomic
|
|
|
|
// block doesn't give us an actual fine-grain atomic block, the
|
|
|
|
// code essentially forces the atomic block to span across the
|
|
|
|
// entire function in the presence of recursion. The fine
|
|
|
|
// granularity might lead to smaller atomic blocks in the
|
|
|
|
// absence of recursion consequently leading to smaller windows
|
|
|
|
// of contention among concurrent transactions.
|
|
|
|
//
|
|
|
|
// Haven't atomized kernel version functions since that "might"
|
|
|
|
// lead to undesirable interactions with other kernel
|
|
|
|
// components.
|
|
|
|
//
|
|
|
|
|
|
|
|
//#define BREAK_ON_FAILURE
|
|
|
|
//#define CHECK_TRAVERSE_ACCESS
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Text;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Threading;
|
|
|
|
using Microsoft.SingSharp;
|
|
|
|
using Microsoft.Singularity;
|
|
|
|
using Microsoft.Singularity.Io;
|
|
|
|
using Microsoft.Singularity.Channels;
|
|
|
|
using Microsoft.Singularity.Directory;
|
|
|
|
using Microsoft.Singularity.Security;
|
|
|
|
|
|
|
|
#if !SINGULARITY_PROCESS
|
|
|
|
namespace Microsoft.Singularity.Directory
|
|
|
|
#else
|
|
|
|
using Microsoft.Singularity;
|
|
|
|
using Microsoft.Singularity.V1.Services;
|
|
|
|
namespace Microsoft.Application.DSP
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
#if SINGULARITY_PROCESS
|
|
|
|
public class Kernel
|
|
|
|
{
|
|
|
|
public static void Waypoint(int num)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
public class DirNode : Node
|
|
|
|
{
|
|
|
|
public readonly SortedList! names;
|
|
|
|
private Hashtable! notificationList;
|
|
|
|
private StringBuilder sb;
|
|
|
|
|
|
|
|
private Mutex! dirMutex;
|
|
|
|
|
|
|
|
public void AcquireLock()
|
|
|
|
{
|
|
|
|
dirMutex.WaitOne();
|
|
|
|
}
|
|
|
|
public void ReleaseLock()
|
|
|
|
{
|
|
|
|
dirMutex.ReleaseMutex();
|
|
|
|
}
|
|
|
|
|
|
|
|
public DirNode(string! name, Node! parent)
|
|
|
|
{
|
|
|
|
names = new SortedList();
|
|
|
|
dirMutex = new Mutex();
|
|
|
|
notificationList = new Hashtable();
|
|
|
|
sb = new StringBuilder(256);
|
|
|
|
base(NodeType.Directory, name, parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
public DirNode(string! name, AclCore! core, IAclPolicy! policy)
|
|
|
|
{
|
|
|
|
names = new SortedList();
|
|
|
|
dirMutex = new Mutex();
|
|
|
|
notificationList = new Hashtable();
|
|
|
|
sb = new StringBuilder(256);
|
|
|
|
base(NodeType.Directory, name, core, policy);
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// begin kernel only functions
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if !SINGULARITY_PROCESS
|
|
|
|
public bool CreateDirectory(string! name, out ErrorCode error)
|
|
|
|
{
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
bool success = false;
|
|
|
|
AcquireLock();
|
|
|
|
if (names.ContainsKey(name)) {
|
|
|
|
success = false;
|
|
|
|
error = ErrorCode.AlreadyExists;
|
|
|
|
DebugStub.Break();
|
|
|
|
ReleaseLock();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DirNode d = new DirNode(name, this);
|
|
|
|
Tracing.Log(Tracing.Debug,"createDir: parent="+name);
|
|
|
|
names.Add(name,d);
|
|
|
|
HandleNotification(name,NotifyType.Creation);
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
ReleaseLock();
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool CreateLink(string! name, string! val)
|
|
|
|
{
|
|
|
|
bool success = false;
|
|
|
|
AcquireLock();
|
|
|
|
if (names.ContainsKey(name)) {
|
|
|
|
success = false;
|
|
|
|
#if BREAK_ON_FAILURE
|
|
|
|
DebugStub.Break();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SymLinkNode sym = new SymLinkNode(val, name, this);
|
|
|
|
names.Add(name,sym);
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
ReleaseLock();
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
public DirNode FindDirectory(StringBuilder! p)
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
//
|
|
|
|
// sb.Append("\nFindDirectory ");
|
|
|
|
// sb.Append(SbUtils.PathString(p));
|
|
|
|
// sb.Append(" at dir ");
|
|
|
|
// sb.Append(this.NodeName);
|
|
|
|
// DebugStub.WriteLine(sb.ToString());
|
|
|
|
// Tracing.Log(Tracing.Debug,sb.ToString());
|
|
|
|
//
|
2008-03-05 09:52:00 -05:00
|
|
|
if (p.Length == 0) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
string first = SbUtils.FirstElement(p);
|
2008-11-17 18:29:00 -05:00
|
|
|
//
|
|
|
|
// sb.Length = 0;
|
|
|
|
// sb.Append(" findDir: p=");
|
|
|
|
// sb.Append(p.ToString());
|
|
|
|
// sb.Append(" First=");
|
|
|
|
// sb.Append(first);
|
|
|
|
// DebugStub.WriteLine(sb.ToString());
|
|
|
|
//
|
2008-03-05 09:52:00 -05:00
|
|
|
//DebugStub.Break();
|
|
|
|
if (null == first) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
Node n = (Node)this.names[first];
|
|
|
|
if (null == n) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
p = SbUtils.RemoveFirstElement(p);
|
2008-11-17 18:29:00 -05:00
|
|
|
//
|
|
|
|
// sb.Length = 0;
|
|
|
|
// sb.Append(" afterRemove: p=");
|
|
|
|
// sb.Append(p.ToString());
|
|
|
|
// sb.Append(" First=");
|
|
|
|
// sb.Append(first);
|
|
|
|
// DebugStub.WriteLine(sb.ToString());
|
|
|
|
//
|
2008-03-05 09:52:00 -05:00
|
|
|
if (n is DirNode) {
|
|
|
|
return ((DirNode) n).FindDirectory(p);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//DebugStub.Break();
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <returns>
|
|
|
|
/// Special kernel interface for adding in memory images to the namespace.
|
|
|
|
/// </returns>
|
|
|
|
public bool RegisterIoMemory(string! name, IoMemory! ioMemory)
|
|
|
|
{
|
|
|
|
Tracing.Log(Tracing.Debug,"RegisterIoMemory: "+name+" in "+name+" VA:{0} Len:{1}",
|
|
|
|
ioMemory.VirtualAddress, (UIntPtr)ioMemory.Length);
|
|
|
|
|
|
|
|
if (ioMemory.VirtualAddress == UIntPtr.Zero) {
|
|
|
|
DebugStub.Break();
|
|
|
|
}
|
|
|
|
bool success = false;
|
|
|
|
try {
|
|
|
|
this.AcquireLock();
|
|
|
|
this.names.Add(name, new IoMemoryNode(ioMemory, name, this));
|
|
|
|
success = true; //success
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
this.ReleaseLock();
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// end kernel only functions
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
public override bool GetAttributes(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link,
|
|
|
|
out long length,
|
|
|
|
out NodeType nodeType
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Kernel.Waypoint(3050);
|
|
|
|
|
|
|
|
atomic {
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
length = 0;
|
|
|
|
linkFound = false;
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
nodeType = NodeType.BadNode;
|
|
|
|
|
|
|
|
if (CheckEmpty(p)) {
|
|
|
|
|
|
|
|
//the user wants the attributes of the directory object
|
|
|
|
Kernel.Waypoint(3051);
|
|
|
|
Kernel.Waypoint(3052);
|
|
|
|
//check read access for this object
|
|
|
|
if (!CheckAccess(DirPermissions.AccessModeRead, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nodeType = NodeType.Directory;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// there is more path, continue processing
|
|
|
|
string first = SbUtils.FirstElement(p);
|
|
|
|
if (null == first) {
|
|
|
|
error = ErrorCode.NotFound;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// can the caller traverse the current node?
|
|
|
|
Kernel.Waypoint(3052);
|
|
|
|
#if CHECK_TRAVERSE_ACCESS
|
|
|
|
if (!CheckAccess(DirPermissions.AccessModeTraverse, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
Kernel.Waypoint(3053);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
Kernel.Waypoint(3054);
|
|
|
|
Node n = (Node)this.names[first];
|
|
|
|
if (null == n) {
|
|
|
|
error = ErrorCode.NotFound;
|
|
|
|
nodeType = NodeType.BadNode;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = SbUtils.RemoveFirstElement(p);
|
|
|
|
Kernel.Waypoint(3055);
|
|
|
|
bool ok = n.GetAttributes(p,
|
|
|
|
pr,
|
|
|
|
out linkFound,
|
|
|
|
out error,
|
|
|
|
out reparse,
|
|
|
|
out link,
|
|
|
|
out length,
|
|
|
|
out nodeType
|
|
|
|
);
|
|
|
|
|
|
|
|
Kernel.Waypoint(3056);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private 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);
|
|
|
|
}
|
2008-11-17 18:29:00 -05:00
|
|
|
else if (starPos == pattern.Length - 1) {
|
2008-03-05 09:52:00 -05:00
|
|
|
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.WriteLine("name={0} pre={1} post={2} match={3}",
|
|
|
|
// __arglist(name, prefix, postfix, match));
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void HandleNotification(string! name, NotifyType type)
|
|
|
|
{
|
|
|
|
if (notificationList == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (DictionaryEntry n in notificationList) {
|
|
|
|
string pattern = (string!) n.Key;
|
|
|
|
bool match = isMatch (name,pattern);
|
|
|
|
|
|
|
|
if (match) {
|
|
|
|
NotifyContract.Imp notifyEP =
|
|
|
|
((TRef <NotifyContract.Imp:Notify>!) n.Value).Acquire();
|
|
|
|
assert notifyEP.InState(NotifyContract.Notify.Value);
|
|
|
|
notifyEP.SendChangeNotification(Bitter.FromString2(name),type);
|
2008-11-17 18:29:00 -05:00
|
|
|
// TODO: should really be a switch receive
|
2008-03-05 09:52:00 -05:00
|
|
|
notifyEP.RecvAckChangeNotification();
|
|
|
|
Tracing.Log(Tracing.Debug,"notifying: pattern="+pattern+" path="+name+" type="+type);
|
|
|
|
((TRef <NotifyContract.Imp:Notify>!) n.Value).Release(notifyEP);
|
|
|
|
}
|
|
|
|
} //foreach
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <returns>
|
|
|
|
/// null on success, the service argument if it failed.
|
|
|
|
/// </returns>
|
|
|
|
public override ServiceContract.Exp Bind(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
out bool success,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link,
|
|
|
|
[Claims] ServiceContract.Exp! service)
|
|
|
|
{
|
|
|
|
Tracing.Log(Tracing.Debug, "bind "+ SbUtils.PathString(p));
|
|
|
|
Kernel.Waypoint(3000);
|
|
|
|
|
|
|
|
atomic {
|
|
|
|
success = false;
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
|
|
|
|
if (CheckEmpty(p)) {
|
|
|
|
//the user wants to bind to a directory object in the namespace
|
|
|
|
Kernel.Waypoint(3001);
|
|
|
|
DirectoryServiceContract.Exp dirEP = service as DirectoryServiceContract.Exp;
|
|
|
|
Kernel.Waypoint(3002);
|
|
|
|
if (dirEP != null) {
|
|
|
|
// check Traverse access for both caller and supplied EP
|
|
|
|
#if CHECK_TRAVERSE_ACCESS
|
|
|
|
if (!CheckAccess(DirPermissions.AccessModeTraverse, pr, service)) {
|
|
|
|
DebugStub.WriteLine("No access to DirectoryService.Bind");
|
|
|
|
Kernel.Waypoint(3003);
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return service;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//Tracing.Log(Tracing.Debug," found '/' starting dir worker");
|
|
|
|
Kernel.Waypoint(3004);
|
|
|
|
|
|
|
|
DirectoryServiceWorker.Create(this, dirEP);
|
|
|
|
|
|
|
|
Kernel.Waypoint(3005);
|
|
|
|
success = true;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
error = ErrorCode.ContractNotSupported;
|
|
|
|
return service;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Kernel.Waypoint(3006);
|
|
|
|
Node n = GetNextNode(p, pr, out error);
|
|
|
|
if (null == n) {
|
|
|
|
return service;
|
|
|
|
}
|
|
|
|
|
|
|
|
Kernel.Waypoint(3009);
|
|
|
|
ServiceContract.Exp sp = n.Bind(p,
|
|
|
|
pr,
|
|
|
|
out success,
|
|
|
|
out linkFound,
|
|
|
|
out error,
|
|
|
|
out reparse,
|
|
|
|
out link, service);
|
|
|
|
Kernel.Waypoint(3010);
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override ServiceProviderContract.Imp Register(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
[Claims] ServiceProviderContract.Imp! sp,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link
|
|
|
|
)
|
|
|
|
{
|
|
|
|
bool firstFound;
|
|
|
|
Node n;
|
|
|
|
|
|
|
|
#if !SINGULARITY_PROCESS
|
|
|
|
Tracing.Log(Tracing.Debug,"({1:x8}) Register: path ={0}\n",
|
|
|
|
SbUtils.PathString(p),(UIntPtr)Kernel.AddressOf(Thread.CurrentThread));
|
|
|
|
#endif
|
|
|
|
atomic {
|
|
|
|
reparse = false;
|
|
|
|
linkFound = false;
|
|
|
|
link = null;
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
if (CheckEmpty(p)) {
|
2008-03-05 09:52:00 -05:00
|
|
|
error = ErrorCode.NotFound;
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SbUtils.IsTail(p)) {
|
|
|
|
string! name = (!)SbUtils.FirstElement(p);
|
|
|
|
if (names.ContainsKey(name)) {
|
|
|
|
error = ErrorCode.AlreadyExists;
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check register access for both caller and EP
|
|
|
|
else if (!CheckAccess(DirPermissions.AccessModeRegister, pr, sp)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
HandleNotification(name, NotifyType.Creation);
|
|
|
|
this.names.Add(name, new ProviderNode(sp, name, this));
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
n = GetNextNode(p, pr, out error);
|
|
|
|
if (n == null) {
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
return n.Register(p, pr, sp, out linkFound, out error, out reparse, out link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <returns>
|
|
|
|
/// The endpoint on success, null, if it fails.
|
|
|
|
/// </returns>
|
|
|
|
public override ServiceProviderContract.Imp:Start Deregister(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
DirectoryServiceContract.Exp! ep,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
bool firstFound;
|
|
|
|
Node n;
|
|
|
|
|
|
|
|
#if !SINGULARITY_PROCESS
|
|
|
|
Tracing.Log(Tracing.Debug,"({1:x8}) DeRegister: path ={0}\n",
|
|
|
|
SbUtils.PathString(p),(UIntPtr)Kernel.AddressOf(Thread.CurrentThread));
|
|
|
|
#endif
|
|
|
|
atomic {
|
|
|
|
reparse = false;
|
|
|
|
linkFound = false;
|
|
|
|
link = null;
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
if (CheckEmpty(p)) {
|
2008-03-05 09:52:00 -05:00
|
|
|
error = ErrorCode.NotFound;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SbUtils.IsTail(p)) {
|
|
|
|
string! name = (!)SbUtils.FirstElement(p);
|
|
|
|
if (!names.ContainsKey(name)) {
|
|
|
|
error = ErrorCode.NotFound;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
// check deregister access of caller
|
|
|
|
else if (!CheckAccess(DirPermissions.AccessModeDeregister, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
HandleNotification(name, NotifyType.Deletion);
|
|
|
|
n = (Node) names[name];
|
|
|
|
if (n != null && n is ProviderNode) {
|
|
|
|
ServiceProviderContract.Imp:Start sp = ((ProviderNode) n).GetServiceEndpoint();
|
|
|
|
names.Remove(name);
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
error = ErrorCode.NotProvider;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
n = GetNextNode(p, pr, out error);
|
|
|
|
if (n == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return n.Deregister(p, pr, ep, out linkFound, out error, out reparse, out link);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Local Enumeration Records. We need this
|
|
|
|
// because we don't want to do ExHeap allocations in an
|
|
|
|
// atomic block (due to the resulting side effects) in
|
|
|
|
// the Enumerate() method below.
|
|
|
|
struct LocalEnumerationRecords
|
|
|
|
{
|
|
|
|
public string Path;
|
|
|
|
public NodeType Type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <returns>
|
|
|
|
/// The a vector of vectors if success, null, if it fails.
|
|
|
|
/// </returns>
|
|
|
|
public EnumerationRecords[] in ExHeap Enumerate(Principal pr, out ErrorCode error)
|
|
|
|
{
|
|
|
|
error = ErrorCode.Unknown;
|
|
|
|
|
|
|
|
// check read access for directory enumerate
|
|
|
|
if (!CheckAccess(DirPermissions.AccessModeRead, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
// Store the enumeration in a local vector
|
2008-03-05 09:52:00 -05:00
|
|
|
// from within the atomic block, and after the
|
|
|
|
// atomic block succeeds copy the local vector to
|
|
|
|
// the ExHeap buffer that is used to send out the
|
|
|
|
// enumeration
|
|
|
|
EnumerationRecords[] in ExHeap responses;
|
|
|
|
|
|
|
|
LocalEnumerationRecords[] localResponses;
|
|
|
|
|
|
|
|
atomic {
|
|
|
|
error = ErrorCode.Unknown;
|
|
|
|
localResponses = new LocalEnumerationRecords[names.Count];
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
for (int i = 0; i < names.Count; i++) {
|
2008-03-05 09:52:00 -05:00
|
|
|
localResponses[i].Path = (!) (string)names.GetKey(i);
|
|
|
|
localResponses[i].Type = ((!) (Node)names.GetByIndex(i)).Type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
responses = new [ExHeap] EnumerationRecords[localResponses.Length];
|
2008-11-17 18:29:00 -05:00
|
|
|
for (int i = 0; i < localResponses.Length; i++) {
|
2008-03-05 09:52:00 -05:00
|
|
|
expose (responses[i]) {
|
|
|
|
delete responses[i].Path; // checker doesn't know its null.
|
|
|
|
responses[i].Path =
|
|
|
|
Bitter.FromString2((!) localResponses[i].Path);
|
|
|
|
responses[i].Type = localResponses[i].Type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return responses;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <returns>
|
|
|
|
/// true on success, false, if it fails.
|
|
|
|
/// </returns>
|
|
|
|
public override NotifyContract.Imp Notify(StringBuilder! path,
|
|
|
|
Principal pr,
|
|
|
|
string! pattern,
|
|
|
|
bool sendExisting,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link,
|
|
|
|
[Claims] NotifyContract.Imp! notifyImp)
|
|
|
|
{
|
|
|
|
//DebugStub.WriteLine(" dir Notify() sb.len={0}, s={1}",__arglist(pathSpec.Length,pathSpec.ToString()));
|
|
|
|
atomic {
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
|
|
|
|
if (path.Length == 0) {
|
|
|
|
// got it!
|
|
|
|
DebugStub.Break();
|
|
|
|
return notifyImp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SbUtils.IsTail(path)) {
|
|
|
|
string! first = (!)SbUtils.FirstElement(path);
|
|
|
|
|
|
|
|
// check access: can the caller AND dest EP received notifications for this object
|
|
|
|
if (!CheckAccess(DirPermissions.AccessModeNotify, pr, notifyImp)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return notifyImp;
|
|
|
|
}
|
|
|
|
notifyImp.SendBegin();
|
|
|
|
TRef <NotifyContract.Imp:Notify> notifyEP =
|
|
|
|
new TRef <NotifyContract.Imp:Notify> (notifyImp);
|
|
|
|
|
|
|
|
notificationList.Add(first,notifyEP);
|
|
|
|
Tracing.Log(Tracing.Debug,"notify: pattern="+first);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// check access: can the caller traverse the current folder
|
|
|
|
#if CHECK_TRAVERSE_ACCESS
|
|
|
|
if (!CheckAccess(DirPermissions.AccessModeTraverse, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return notifyImp;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
string first = SbUtils.FirstElement(path);
|
|
|
|
sb.Length = 0;
|
|
|
|
sb.Append(" dirnode Notify: str=");
|
|
|
|
sb.Append(path.ToString());
|
|
|
|
sb.Append(" first = ");
|
|
|
|
sb.Append(first);
|
|
|
|
//DebugStub.WriteLine(sb.ToString());
|
|
|
|
|
|
|
|
Node n = (Node)this.names[first];
|
|
|
|
if (null == n) {
|
|
|
|
DebugStub.Break();
|
|
|
|
return notifyImp;
|
|
|
|
}
|
|
|
|
|
|
|
|
path = SbUtils.RemoveFirstElement(path);
|
|
|
|
return n.Notify(path, pr, pattern, sendExisting,
|
|
|
|
out linkFound, out error, out reparse, out link, notifyImp);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override FileContract.Imp CreateAndBindFile(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link
|
|
|
|
)
|
|
|
|
{
|
|
|
|
linkFound = false;
|
|
|
|
error = ErrorCode.NotImplemented;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool CreateDirectory(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Node n;
|
|
|
|
|
|
|
|
atomic {
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
|
|
|
|
if (SbUtils.IsTail(p)) {
|
|
|
|
string! name = (!)SbUtils.FirstElement(p);
|
|
|
|
if (names.ContainsKey(name)) {
|
|
|
|
error = ErrorCode.AlreadyExists;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// check write access to parent
|
|
|
|
if (!CheckAccess(DirPermissions.AccessModeWrite, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DirNode d = new DirNode(name, this);
|
|
|
|
Tracing.Log(Tracing.Debug,"createDir: parent="+name);
|
|
|
|
names.Add(name,d);
|
2008-11-17 18:29:00 -05:00
|
|
|
// Not sure if this is needed
|
2008-03-05 09:52:00 -05:00
|
|
|
// here, maybe needed only for
|
|
|
|
// Registering and Deregistering
|
|
|
|
// services; hence commenting out
|
|
|
|
// the notification part
|
|
|
|
//HandleNotification(name, NotifyType.Creation);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// pass the request on to the next node if there is one.
|
|
|
|
if (CheckEmpty(p)) {
|
|
|
|
error = ErrorCode.NotFound;
|
|
|
|
DebugStub.Break();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
n = GetNextNode(p, pr, out error);
|
|
|
|
if (n == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return ((!)n).CreateDirectory(p, pr, out linkFound, out error, out reparse, out link);
|
|
|
|
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool CreateFile(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Node n;
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
|
|
|
|
// since the function implementation (commented out
|
|
|
|
// below) always returns a "false" value and does
|
|
|
|
// not update the system state, we'll simply return
|
|
|
|
// a "false" value here itself
|
|
|
|
return false;
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
//
|
|
|
|
//if (SbUtils.IsTail(p)) {
|
|
|
|
// // true files are not supported in the namespace
|
|
|
|
// error = ErrorCode.NotImplemented;
|
|
|
|
// return false;
|
|
|
|
//}
|
|
|
|
//else {
|
|
|
|
// // pass the request on to the next node if there is one.
|
|
|
|
// if (CheckEmpty(p)) {
|
|
|
|
// error = ErrorCode.NotImplemented;
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
// n = GetNextNode(p, pr, out error);
|
|
|
|
// if (n == null) {
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
// return ((!)n).CreateFile(p, pr, out linkFound, out error, out reparse, out link);
|
|
|
|
//
|
|
|
|
//}
|
|
|
|
//return false;
|
|
|
|
//
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
private bool CheckEmpty(StringBuilder! p)
|
|
|
|
{
|
2008-11-17 18:29:00 -05:00
|
|
|
if ((p.Length == 0) || ((p.Length == 1) && (p[0] == '/'))) {
|
2008-03-05 09:52:00 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Node GetNextNode(StringBuilder! p, Principal pr, out ErrorCode error)
|
|
|
|
{
|
|
|
|
//DebugStub.Break();
|
|
|
|
string first = SbUtils.FirstElement(p);
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
if (null == first) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
Kernel.Waypoint(3006);
|
|
|
|
#if CHECK_TRAVERSE_ACCESS
|
|
|
|
if (!CheckAccess(DirPermissions.AccessModeTraverse, pr)) {
|
|
|
|
Kernel.Waypoint(3007);
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
Kernel.Waypoint(3008);
|
|
|
|
|
|
|
|
Node n = (Node)this.names[first];
|
|
|
|
if (null == n) {
|
|
|
|
error = ErrorCode.NotFound;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
SbUtils.RemoveFirstElement(p);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool CreateLink(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
string! value,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Node n;
|
|
|
|
atomic {
|
|
|
|
linkFound = false;
|
|
|
|
link = null;
|
|
|
|
reparse = false;
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
|
|
|
|
if (SbUtils.IsTail(p)) {
|
|
|
|
string! name = (!)SbUtils.FirstElement(p);
|
|
|
|
if (names.ContainsKey(name)) {
|
|
|
|
error = ErrorCode.AlreadyExists;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// check write access to parent
|
|
|
|
else if (!CheckAccess(DirPermissions.AccessModeWrite, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SymLinkNode sym = new SymLinkNode(value, name, this);
|
|
|
|
names.Add(name,sym);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { //recurse
|
|
|
|
if (CheckEmpty(p)) {
|
|
|
|
error = ErrorCode.NotFound;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
n = GetNextNode(p, pr, out error);
|
|
|
|
if (n == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return ((!)n).CreateLink(p, pr, value, out linkFound, out error, out reparse, out link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool DeleteDirectory(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Node n;
|
|
|
|
|
|
|
|
DirNode child;
|
|
|
|
|
|
|
|
atomic {
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
error = ErrorCode.NotFound;
|
|
|
|
if (CheckEmpty(p)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SbUtils.IsTail(p)) {
|
|
|
|
string! name = (!)SbUtils.FirstElement(p);
|
|
|
|
if (names.ContainsKey(name)) {
|
|
|
|
// check to see if this node has entries
|
|
|
|
// if so let the caller know
|
|
|
|
n = GetNextNode(p, pr, out error);
|
|
|
|
if (n == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (n is DirNode) {
|
|
|
|
child = (DirNode) n;
|
|
|
|
if (child.names.Count != 0) {
|
|
|
|
DebugStub.WriteLine("Directory is not empty({0})!", __arglist(child.names.Count));
|
|
|
|
error = ErrorCode.DirectoryNotEmpty;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// check write access to parent
|
|
|
|
else if (!CheckAccess(DirPermissions.AccessModeWrite, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// check write access to child
|
|
|
|
else if (!n.CheckAccess(DirPermissions.AccessModeWrite, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
error = ErrorCode.NotDirectory;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
names.Remove(name);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n = GetNextNode(p, pr, out error);
|
|
|
|
if (n == null) {
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return ((!)n).DeleteDirectory(p, pr, out linkFound, out error, out reparse, out link);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool DeleteFile(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Node n;
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
error = ErrorCode.NotFound;
|
|
|
|
|
|
|
|
// since the function implementation (commented out
|
|
|
|
// below) always returns a "false" value and does
|
|
|
|
// not update the system state, we'll simply return
|
|
|
|
// a "false" value here itself
|
|
|
|
return false;
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
//
|
|
|
|
//if (CheckEmpty(p)) {
|
|
|
|
// error = ErrorCode.NotFound;
|
|
|
|
// return false;
|
|
|
|
//}
|
|
|
|
//if (SbUtils.IsTail(p)) {
|
|
|
|
// string! name = (!)SbUtils.FirstElement(p);
|
|
|
|
// if (names.ContainsKey(name)) {
|
|
|
|
// // check write access to parent
|
|
|
|
// if (!CheckAccess(DirPermissions.AccessModeWrite, pr)) {
|
|
|
|
// error = ErrorCode.AccessDenied;
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
// // continue on to actual node for deletion
|
|
|
|
// }
|
|
|
|
// else {
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//n = GetNextNode(p, pr, out error);
|
|
|
|
//if (n == null) {
|
|
|
|
// return false;
|
|
|
|
//}
|
|
|
|
//return ((!)n).DeleteFile(p, pr, out linkFound, out error, out reparse, out link);
|
|
|
|
//
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public override bool DeleteLink(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
Node n;
|
|
|
|
|
|
|
|
//DebugStub.Break();
|
|
|
|
|
|
|
|
atomic {
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
error = ErrorCode.NotFound;
|
|
|
|
if (CheckEmpty(p)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SbUtils.IsTail(p)) {
|
|
|
|
string! name = (!)SbUtils.FirstElement(p);
|
|
|
|
if (names.ContainsKey(name)) {
|
|
|
|
//check write access to parent
|
|
|
|
if (!CheckAccess(DirPermissions.AccessModeWrite, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
// this should check whether the node is a link!
|
|
|
|
names.Remove(name);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n = GetNextNode(p, pr, out error);
|
|
|
|
if (n == null) {
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return ((!)n).DeleteLink(p, pr, out linkFound, out error, out reparse, out link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool GetLinkValue(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
Node n;
|
|
|
|
|
|
|
|
atomic {
|
|
|
|
error = ErrorCode.NotLink;
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
|
|
|
|
//DebugStub.Break();
|
|
|
|
if (CheckEmpty(p)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = GetNextNode(p, pr, out error);
|
|
|
|
if (n == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return ((!)n).GetLinkValue(p, pr, out linkFound, out error, out reparse, out link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override bool QueryACL(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link,
|
|
|
|
out Acl acl
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Node n;
|
|
|
|
|
|
|
|
acl = new Acl();
|
|
|
|
|
|
|
|
atomic {
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
if (CheckEmpty(p)) {
|
|
|
|
if (CheckAccess(DirPermissions.AccessModeRead, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
acl = this.GetInstanceAcl();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
n = GetNextNode(p, pr, out error);
|
|
|
|
if (n == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return ((!)n).QueryACL(p, pr, out linkFound, out error, out reparse, out link, out acl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool StoreACL(StringBuilder! p,
|
|
|
|
Principal pr,
|
|
|
|
Acl acl,
|
|
|
|
out bool linkFound,
|
|
|
|
out ErrorCode error,
|
|
|
|
out bool reparse,
|
|
|
|
out string link
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Node n;
|
|
|
|
|
|
|
|
atomic {
|
|
|
|
linkFound = false;
|
|
|
|
reparse = false;
|
|
|
|
link = null;
|
|
|
|
error = ErrorCode.NoError;
|
|
|
|
|
|
|
|
if (CheckEmpty(p)) {
|
|
|
|
if (!CheckAccess(DirPermissions.AccessModeSetAcl, pr)) {
|
|
|
|
error = ErrorCode.AccessDenied;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
SetInstanceAcl(acl);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
n = GetNextNode(p, pr, out error);
|
|
|
|
if (n == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return ((!)n).StoreACL(p, pr, acl, out linkFound, out error, out reparse, out link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|