First version
This commit is contained in:
270
example/HelloFS/HelloFS.cs
Normal file
270
example/HelloFS/HelloFS.cs
Normal file
@@ -0,0 +1,270 @@
|
||||
//
|
||||
// HelloFS.cs
|
||||
//
|
||||
// Authors:
|
||||
// Jonathan Pryor (jonpryor@vt.edu)
|
||||
//
|
||||
// (C) 2006 Jonathan Pryor
|
||||
//
|
||||
// Mono.Fuse.NETStandard example program
|
||||
//
|
||||
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Mono.Unix.Native;
|
||||
|
||||
namespace Mono.Fuse.NETStandard.Samples {
|
||||
internal class HelloFs : FileSystem {
|
||||
static readonly byte[] hello_str = Encoding.UTF8.GetBytes ("Hello World!\n");
|
||||
const string hello_path = "/hello";
|
||||
const string data_path = "/data";
|
||||
const string data_im_path = "/data.im";
|
||||
|
||||
const int data_size = 100000000;
|
||||
|
||||
byte[] data_im_str;
|
||||
bool have_data_im = false;
|
||||
object data_im_str_lock = new object ();
|
||||
Dictionary<string, byte[]> hello_attrs = new Dictionary<string, byte[]>();
|
||||
|
||||
public HelloFs ()
|
||||
{
|
||||
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
|
||||
Trace.WriteLine ("(HelloFS creating)");
|
||||
hello_attrs ["foo"] = Encoding.UTF8.GetBytes ("bar");
|
||||
}
|
||||
|
||||
protected override Errno OnGetPathStatus (string path, out Stat stbuf)
|
||||
{
|
||||
Trace.WriteLine ("(OnGetPathStatus {0})", path);
|
||||
|
||||
stbuf = new Stat ();
|
||||
switch (path) {
|
||||
case "/":
|
||||
stbuf.st_mode = FilePermissions.S_IFDIR |
|
||||
NativeConvert.FromOctalPermissionString ("0755");
|
||||
stbuf.st_nlink = 2;
|
||||
return 0;
|
||||
case hello_path:
|
||||
case data_path:
|
||||
case data_im_path:
|
||||
stbuf.st_mode = FilePermissions.S_IFREG |
|
||||
NativeConvert.FromOctalPermissionString ("0444");
|
||||
stbuf.st_nlink = 1;
|
||||
int size = 0;
|
||||
switch (path) {
|
||||
case hello_path: size = hello_str.Length; break;
|
||||
case data_path:
|
||||
case data_im_path: size = data_size; break;
|
||||
}
|
||||
stbuf.st_size = size;
|
||||
return 0;
|
||||
default:
|
||||
return Errno.ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Errno OnReadDirectory (string path, OpenedPathInfo fi,
|
||||
out IEnumerable<DirectoryEntry> paths)
|
||||
{
|
||||
Trace.WriteLine ("(OnReadDirectory {0})", path);
|
||||
paths = null;
|
||||
if (path != "/")
|
||||
return Errno.ENOENT;
|
||||
|
||||
paths = GetEntries ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private IEnumerable<DirectoryEntry> GetEntries ()
|
||||
{
|
||||
yield return new DirectoryEntry (".");
|
||||
yield return new DirectoryEntry ("..");
|
||||
yield return new DirectoryEntry ("hello");
|
||||
yield return new DirectoryEntry ("data");
|
||||
if (have_data_im)
|
||||
yield return new DirectoryEntry ("data.im");
|
||||
}
|
||||
|
||||
protected override Errno OnOpenHandle (string path, OpenedPathInfo fi)
|
||||
{
|
||||
Trace.WriteLine (string.Format ("(OnOpen {0} Flags={1})", path, fi.OpenFlags));
|
||||
if (path != hello_path && path != data_path && path != data_im_path)
|
||||
return Errno.ENOENT;
|
||||
if (path == data_im_path && !have_data_im)
|
||||
return Errno.ENOENT;
|
||||
if (fi.OpenAccess != OpenFlags.O_RDONLY)
|
||||
return Errno.EACCES;
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnReadHandle (string path, OpenedPathInfo fi, byte[] buf, long offset, out int bytesWritten)
|
||||
{
|
||||
Trace.WriteLine ("(OnRead {0})", path);
|
||||
bytesWritten = 0;
|
||||
int size = buf.Length;
|
||||
if (path == data_im_path)
|
||||
FillData ();
|
||||
if (path == hello_path || path == data_im_path) {
|
||||
byte[] source = path == hello_path ? hello_str : data_im_str;
|
||||
if (offset < (long) source.Length) {
|
||||
if (offset + (long) size > (long) source.Length)
|
||||
size = (int) ((long) source.Length - offset);
|
||||
Buffer.BlockCopy (source, (int) offset, buf, 0, size);
|
||||
}
|
||||
else
|
||||
size = 0;
|
||||
}
|
||||
else if (path == data_path) {
|
||||
int max = System.Math.Min ((int) data_size, (int) (offset + buf.Length));
|
||||
for (int i = 0, j = (int) offset; j < max; ++i, ++j) {
|
||||
if ((j % 27) == 0)
|
||||
buf [i] = (byte) '\n';
|
||||
else
|
||||
buf [i] = (byte) ((j % 26) + 'a');
|
||||
}
|
||||
}
|
||||
else
|
||||
return Errno.ENOENT;
|
||||
|
||||
bytesWritten = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnGetPathExtendedAttribute (string path, string name, byte[] value, out int bytesWritten)
|
||||
{
|
||||
Trace.WriteLine ("(OnGetPathExtendedAttribute {0})", path);
|
||||
bytesWritten = 0;
|
||||
if (path != hello_path) {
|
||||
return 0;
|
||||
}
|
||||
byte[] _value;
|
||||
lock (hello_attrs) {
|
||||
if (!hello_attrs.ContainsKey (name))
|
||||
return 0;
|
||||
_value = hello_attrs [name];
|
||||
}
|
||||
if (value.Length < _value.Length) {
|
||||
return Errno.ERANGE;
|
||||
}
|
||||
Array.Copy (_value, value, _value.Length);
|
||||
bytesWritten = _value.Length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnSetPathExtendedAttribute (string path, string name, byte[] value, XattrFlags flags)
|
||||
{
|
||||
Trace.WriteLine ("(OnSetPathExtendedAttribute {0})", path);
|
||||
if (path != hello_path) {
|
||||
return Errno.ENOSPC;
|
||||
}
|
||||
lock (hello_attrs) {
|
||||
hello_attrs [name] = value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnRemovePathExtendedAttribute (string path, string name)
|
||||
{
|
||||
Trace.WriteLine ("(OnRemovePathExtendedAttribute {0})", path);
|
||||
if (path != hello_path)
|
||||
return Errno.ENODATA;
|
||||
lock (hello_attrs) {
|
||||
if (!hello_attrs.ContainsKey (name))
|
||||
return Errno.ENODATA;
|
||||
hello_attrs.Remove (name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnListPathExtendedAttributes (string path, out string[] names)
|
||||
{
|
||||
Trace.WriteLine ("(OnListPathExtendedAttributes {0})", path);
|
||||
if (path != hello_path) {
|
||||
names = new string[]{};
|
||||
return 0;
|
||||
}
|
||||
List<string> _names = new List<string> ();
|
||||
lock (hello_attrs) {
|
||||
_names.AddRange (hello_attrs.Keys);
|
||||
}
|
||||
names = _names.ToArray ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private bool ParseArguments (string[] args)
|
||||
{
|
||||
for (int i = 0; i < args.Length; ++i) {
|
||||
switch (args [i]) {
|
||||
case "--data.im-in-memory":
|
||||
have_data_im = true;
|
||||
break;
|
||||
case "-h":
|
||||
case "--help":
|
||||
Console.Error.WriteLine ("usage: hellofs [options] mountpoint");
|
||||
FileSystem.ShowFuseHelp ("hellofs");
|
||||
Console.Error.WriteLine ("hellofs options:");
|
||||
Console.Error.WriteLine (" --data.im-in-memory Add data.im file");
|
||||
return false;
|
||||
default:
|
||||
base.MountPoint = args [i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void FillData ()
|
||||
{
|
||||
lock (data_im_str_lock) {
|
||||
if (data_im_str != null)
|
||||
return;
|
||||
data_im_str = new byte [data_size];
|
||||
for (int i = 0; i < data_im_str.Length; ++i) {
|
||||
if ((i % 27) == 0)
|
||||
data_im_str [i] = (byte) '\n';
|
||||
else
|
||||
data_im_str [i] = (byte) ((i % 26) + 'a');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Main (string[] args)
|
||||
{
|
||||
using (HelloFs fs = new HelloFs ()) {
|
||||
string[] unhandled = fs.ParseFuseArguments (args);
|
||||
foreach (string key in fs.FuseOptions.Keys) {
|
||||
Console.WriteLine ("Option: {0}={1}", key, fs.FuseOptions [key]);
|
||||
}
|
||||
if (!fs.ParseArguments (unhandled))
|
||||
return;
|
||||
// fs.MountAt ("path" /* , args? */);
|
||||
fs.Start ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
example/HelloFS/HelloFS.csproj
Normal file
13
example/HelloFS/HelloFS.csproj
Normal file
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Mono.Fuse.NETStandard.Samples</RootNamespace>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Mono.Fuse.NETStandard\Mono.Fuse.NETStandard.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0-beta3" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
421
example/RedirectFS-FH/RedirectFS-FH.cs
Normal file
421
example/RedirectFS-FH/RedirectFS-FH.cs
Normal file
@@ -0,0 +1,421 @@
|
||||
//
|
||||
// RedirectFS-FH.cs: Port of
|
||||
// http://fuse.cvs.sourceforge.net/fuse/fuse/example/fusexmp_fh.c?view=log
|
||||
//
|
||||
// Authors:
|
||||
// Jonathan Pryor (jonpryor@vt.edu)
|
||||
//
|
||||
// (C) 2006 Jonathan Pryor
|
||||
//
|
||||
// Mono.Fuse.NETStandard example program
|
||||
//
|
||||
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Mono.Fuse.NETStandard;
|
||||
using Mono.Unix.Native;
|
||||
|
||||
namespace Mono.Fuse.NETStandard.Samples {
|
||||
class RedirectFHFS : FileSystem {
|
||||
|
||||
private string basedir;
|
||||
|
||||
public RedirectFHFS ()
|
||||
{
|
||||
}
|
||||
|
||||
protected override Errno OnGetPathStatus (string path, out Stat buf)
|
||||
{
|
||||
int r = Syscall.lstat (basedir+path, out buf);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnGetHandleStatus (string path, OpenedPathInfo info, out Stat buf)
|
||||
{
|
||||
int r = Syscall.fstat ((int) info.Handle, out buf);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnAccessPath (string path, AccessModes mask)
|
||||
{
|
||||
int r = Syscall.access (basedir+path, mask);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnReadSymbolicLink (string path, out string target)
|
||||
{
|
||||
target = null;
|
||||
StringBuilder buf = new StringBuilder (256);
|
||||
do {
|
||||
int r = Syscall.readlink (basedir+path, buf);
|
||||
if (r < 0) {
|
||||
return Stdlib.GetLastError ();
|
||||
}
|
||||
else if (r == buf.Capacity) {
|
||||
buf.Capacity *= 2;
|
||||
}
|
||||
else {
|
||||
target = buf.ToString (0, r);
|
||||
return 0;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
protected override Errno OnOpenDirectory (string path, OpenedPathInfo info)
|
||||
{
|
||||
IntPtr dp = Syscall.opendir (basedir+path);
|
||||
if (dp == IntPtr.Zero)
|
||||
return Stdlib.GetLastError ();
|
||||
|
||||
info.Handle = dp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnReadDirectory (string path, OpenedPathInfo fi,
|
||||
out IEnumerable<DirectoryEntry> paths)
|
||||
{
|
||||
IntPtr dp = (IntPtr) fi.Handle;
|
||||
|
||||
paths = ReadDirectory (dp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private IEnumerable<DirectoryEntry> ReadDirectory (IntPtr dp)
|
||||
{
|
||||
Dirent de;
|
||||
while ((de = Syscall.readdir (dp)) != null) {
|
||||
DirectoryEntry e = new DirectoryEntry (de.d_name);
|
||||
e.Stat.st_ino = de.d_ino;
|
||||
e.Stat.st_mode = (FilePermissions) (de.d_type << 12);
|
||||
yield return e;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Errno OnReleaseDirectory (string path, OpenedPathInfo info)
|
||||
{
|
||||
IntPtr dp = (IntPtr) info.Handle;
|
||||
Syscall.closedir (dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnCreateSpecialFile (string path, FilePermissions mode, ulong rdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
// On Linux, this could just be `mknod(basedir+path, mode, rdev)' but
|
||||
// this is more portable.
|
||||
if ((mode & FilePermissions.S_IFMT) == FilePermissions.S_IFREG) {
|
||||
r = Syscall.open (basedir+path, OpenFlags.O_CREAT | OpenFlags.O_EXCL |
|
||||
OpenFlags.O_WRONLY, mode);
|
||||
if (r >= 0)
|
||||
r = Syscall.close (r);
|
||||
}
|
||||
else if ((mode & FilePermissions.S_IFMT) == FilePermissions.S_IFIFO) {
|
||||
r = Syscall.mkfifo (basedir+path, mode);
|
||||
}
|
||||
else {
|
||||
r = Syscall.mknod (basedir+path, mode, rdev);
|
||||
}
|
||||
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnCreateDirectory (string path, FilePermissions mode)
|
||||
{
|
||||
int r = Syscall.mkdir (basedir+path, mode);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnRemoveFile (string path)
|
||||
{
|
||||
int r = Syscall.unlink (basedir+path);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnRemoveDirectory (string path)
|
||||
{
|
||||
int r = Syscall.rmdir (basedir+path);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnCreateSymbolicLink (string from, string to)
|
||||
{
|
||||
int r = Syscall.symlink (from, basedir+to);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnRenamePath (string from, string to)
|
||||
{
|
||||
int r = Syscall.rename (basedir+from, basedir+to);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnCreateHardLink (string from, string to)
|
||||
{
|
||||
int r = Syscall.link (basedir+from, basedir+to);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnChangePathPermissions (string path, FilePermissions mode)
|
||||
{
|
||||
int r = Syscall.chmod (basedir+path, mode);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnChangePathOwner (string path, long uid, long gid)
|
||||
{
|
||||
int r = Syscall.lchown (basedir+path, (uint) uid, (uint) gid);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnTruncateFile (string path, long size)
|
||||
{
|
||||
int r = Syscall.truncate (basedir+path, size);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnTruncateHandle (string path, OpenedPathInfo info, long size)
|
||||
{
|
||||
int r = Syscall.ftruncate ((int) info.Handle, size);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnChangePathTimes (string path, ref Utimbuf buf)
|
||||
{
|
||||
int r = Syscall.utime (basedir+path, ref buf);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnCreateHandle (string path, OpenedPathInfo info, FilePermissions mode)
|
||||
{
|
||||
int fd = Syscall.open (basedir+path, info.OpenFlags, mode);
|
||||
if (fd == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
info.Handle = (IntPtr) fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnOpenHandle (string path, OpenedPathInfo info)
|
||||
{
|
||||
int fd = Syscall.open (basedir+path, info.OpenFlags);
|
||||
if (fd == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
info.Handle = (IntPtr) fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override unsafe Errno OnReadHandle (string path, OpenedPathInfo info, byte[] buf,
|
||||
long offset, out int bytesRead)
|
||||
{
|
||||
int r;
|
||||
fixed (byte *pb = buf) {
|
||||
r = bytesRead = (int) Syscall.pread ((int) info.Handle,
|
||||
pb, (ulong) buf.Length, offset);
|
||||
}
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override unsafe Errno OnWriteHandle (string path, OpenedPathInfo info,
|
||||
byte[] buf, long offset, out int bytesWritten)
|
||||
{
|
||||
int r;
|
||||
fixed (byte *pb = buf) {
|
||||
r = bytesWritten = (int) Syscall.pwrite ((int) info.Handle,
|
||||
pb, (ulong) buf.Length, offset);
|
||||
}
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnGetFileSystemStatus (string path, out Statvfs stbuf)
|
||||
{
|
||||
int r = Syscall.statvfs (basedir+path, out stbuf);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnFlushHandle (string path, OpenedPathInfo info)
|
||||
{
|
||||
/* This is called from every close on an open file, so call the
|
||||
close on the underlying filesystem. But since flush may be
|
||||
called multiple times for an open file, this must not really
|
||||
close the file. This is important if used on a network
|
||||
filesystem like NFS which flush the data/metadata on close() */
|
||||
int r = Syscall.close (Syscall.dup ((int) info.Handle));
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnReleaseHandle (string path, OpenedPathInfo info)
|
||||
{
|
||||
int r = Syscall.close ((int) info.Handle);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnSynchronizeHandle (string path, OpenedPathInfo info, bool onlyUserData)
|
||||
{
|
||||
int r;
|
||||
if (onlyUserData)
|
||||
r = Syscall.fdatasync ((int) info.Handle);
|
||||
else
|
||||
r = Syscall.fsync ((int) info.Handle);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnSetPathExtendedAttribute (string path, string name, byte[] value, XattrFlags flags)
|
||||
{
|
||||
int r = Syscall.lsetxattr (basedir+path, name, value, (ulong) value.Length, flags);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnGetPathExtendedAttribute (string path, string name, byte[] value, out int bytesWritten)
|
||||
{
|
||||
int r = bytesWritten = (int) Syscall.lgetxattr (basedir+path, name, value, (ulong) value.Length);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnListPathExtendedAttributes (string path, out string[] names)
|
||||
{
|
||||
int r = (int) Syscall.llistxattr (basedir+path, out names);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnRemovePathExtendedAttribute (string path, string name)
|
||||
{
|
||||
int r = Syscall.lremovexattr (basedir+path, name);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnLockHandle (string file, OpenedPathInfo info, FcntlCommand cmd, ref Flock @lock)
|
||||
{
|
||||
int r = Syscall.fcntl ((int) info.Handle, cmd, ref @lock);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private bool ParseArguments (string[] args)
|
||||
{
|
||||
for (int i = 0; i < args.Length; ++i) {
|
||||
switch (args [i]) {
|
||||
case "-h":
|
||||
case "--help":
|
||||
ShowHelp ();
|
||||
return false;
|
||||
default:
|
||||
if (base.MountPoint == null)
|
||||
base.MountPoint = args [i];
|
||||
else
|
||||
basedir = args [i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (base.MountPoint == null) {
|
||||
return Error ("missing mountpoint");
|
||||
}
|
||||
if (basedir == null) {
|
||||
return Error ("missing basedir");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void ShowHelp ()
|
||||
{
|
||||
Console.Error.WriteLine ("usage: redirectfs [options] mountpoint:");
|
||||
FileSystem.ShowFuseHelp ("redirectfs-fh");
|
||||
Console.Error.WriteLine ();
|
||||
Console.Error.WriteLine ("redirectfs-fh options");
|
||||
Console.Error.WriteLine (" basedir Directory to mirror");
|
||||
}
|
||||
|
||||
private static bool Error (string message)
|
||||
{
|
||||
Console.Error.WriteLine ("redirectfs-fh: error: {0}", message);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Main (string[] args)
|
||||
{
|
||||
using (RedirectFHFS fs = new RedirectFHFS ()) {
|
||||
string[] unhandled = fs.ParseFuseArguments (args);
|
||||
if (!fs.ParseArguments (unhandled))
|
||||
return;
|
||||
fs.Start ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
example/RedirectFS-FH/RedirectFS-FH.csproj
Normal file
19
example/RedirectFS-FH/RedirectFS-FH.csproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Mono.Fuse.NETStandard.Samples</RootNamespace>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Mono.Fuse.NETStandard\Mono.Fuse.NETStandard.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0-beta3" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
368
example/RedirectFS/RedirectFS.cs
Normal file
368
example/RedirectFS/RedirectFS.cs
Normal file
@@ -0,0 +1,368 @@
|
||||
//
|
||||
// RedirectFS.cs: Port of
|
||||
// http://fuse.cvs.sourceforge.net/fuse/fuse/example/fusexmp.c?view=log
|
||||
//
|
||||
// Authors:
|
||||
// Jonathan Pryor (jonpryor@vt.edu)
|
||||
//
|
||||
// (C) 2006 Jonathan Pryor
|
||||
//
|
||||
// Mono.Fuse.NETStandard example program
|
||||
//
|
||||
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Mono.Fuse.NETStandard;
|
||||
using Mono.Unix.Native;
|
||||
|
||||
namespace Mono.Fuse.NETStandard.Samples {
|
||||
class RedirectFS : FileSystem {
|
||||
|
||||
private string basedir;
|
||||
|
||||
public RedirectFS ()
|
||||
{
|
||||
}
|
||||
|
||||
protected override Errno OnGetPathStatus (string path, out Stat buf)
|
||||
{
|
||||
int r = Syscall.lstat (basedir+path, out buf);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnAccessPath (string path, AccessModes mask)
|
||||
{
|
||||
int r = Syscall.access (basedir+path, mask);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnReadSymbolicLink (string path, out string target)
|
||||
{
|
||||
target = null;
|
||||
StringBuilder buf = new StringBuilder (256);
|
||||
do {
|
||||
int r = Syscall.readlink (basedir+path, buf);
|
||||
if (r < 0) {
|
||||
return Stdlib.GetLastError ();
|
||||
}
|
||||
else if (r == buf.Capacity) {
|
||||
buf.Capacity *= 2;
|
||||
}
|
||||
else {
|
||||
target = buf.ToString (0, r);
|
||||
return 0;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
protected override Errno OnReadDirectory (string path, OpenedPathInfo fi,
|
||||
out IEnumerable<DirectoryEntry> paths)
|
||||
{
|
||||
IntPtr dp = Syscall.opendir (basedir+path);
|
||||
if (dp == IntPtr.Zero) {
|
||||
paths = null;
|
||||
return Stdlib.GetLastError ();
|
||||
}
|
||||
|
||||
Dirent de;
|
||||
List<DirectoryEntry> entries = new List<DirectoryEntry> ();
|
||||
while ((de = Syscall.readdir (dp)) != null) {
|
||||
DirectoryEntry e = new DirectoryEntry (de.d_name);
|
||||
e.Stat.st_ino = de.d_ino;
|
||||
e.Stat.st_mode = (FilePermissions) (de.d_type << 12);
|
||||
entries.Add (e);
|
||||
}
|
||||
Syscall.closedir (dp);
|
||||
|
||||
paths = entries;
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnCreateSpecialFile (string path, FilePermissions mode, ulong rdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
// On Linux, this could just be `mknod(basedir+path, mode, rdev)' but this is
|
||||
// more portable.
|
||||
if ((mode & FilePermissions.S_IFMT) == FilePermissions.S_IFREG) {
|
||||
r = Syscall.open (basedir+path, OpenFlags.O_CREAT | OpenFlags.O_EXCL |
|
||||
OpenFlags.O_WRONLY, mode);
|
||||
if (r >= 0)
|
||||
r = Syscall.close (r);
|
||||
}
|
||||
else if ((mode & FilePermissions.S_IFMT) == FilePermissions.S_IFIFO) {
|
||||
r = Syscall.mkfifo (basedir+path, mode);
|
||||
}
|
||||
else {
|
||||
r = Syscall.mknod (basedir+path, mode, rdev);
|
||||
}
|
||||
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnCreateDirectory (string path, FilePermissions mode)
|
||||
{
|
||||
int r = Syscall.mkdir (basedir+path, mode);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnRemoveFile (string path)
|
||||
{
|
||||
int r = Syscall.unlink (basedir+path);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnRemoveDirectory (string path)
|
||||
{
|
||||
int r = Syscall.rmdir (basedir+path);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnCreateSymbolicLink (string from, string to)
|
||||
{
|
||||
int r = Syscall.symlink (from, basedir+to);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnRenamePath (string from, string to)
|
||||
{
|
||||
int r = Syscall.rename (basedir+from, basedir+to);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnCreateHardLink (string from, string to)
|
||||
{
|
||||
int r = Syscall.link (basedir+from, basedir+to);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnChangePathPermissions (string path, FilePermissions mode)
|
||||
{
|
||||
int r = Syscall.chmod (basedir+path, mode);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnChangePathOwner (string path, long uid, long gid)
|
||||
{
|
||||
int r = Syscall.lchown (basedir+path, (uint) uid, (uint) gid);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnTruncateFile (string path, long size)
|
||||
{
|
||||
int r = Syscall.truncate (basedir+path, size);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnChangePathTimes (string path, ref Utimbuf buf)
|
||||
{
|
||||
int r = Syscall.utime (basedir+path, ref buf);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnOpenHandle (string path, OpenedPathInfo info)
|
||||
{
|
||||
return ProcessFile (basedir+path, info.OpenFlags, delegate (int fd) {return 0;});
|
||||
}
|
||||
|
||||
private delegate int FdCb (int fd);
|
||||
private static Errno ProcessFile (string path, OpenFlags flags, FdCb cb)
|
||||
{
|
||||
int fd = Syscall.open (path, flags);
|
||||
if (fd == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
int r = cb (fd);
|
||||
Errno res = 0;
|
||||
if (r == -1)
|
||||
res = Stdlib.GetLastError ();
|
||||
Syscall.close (fd);
|
||||
return res;
|
||||
}
|
||||
|
||||
protected override unsafe Errno OnReadHandle (string path, OpenedPathInfo info, byte[] buf,
|
||||
long offset, out int bytesRead)
|
||||
{
|
||||
int br = 0;
|
||||
Errno e = ProcessFile (basedir+path, OpenFlags.O_RDONLY, delegate (int fd) {
|
||||
fixed (byte *pb = buf) {
|
||||
return br = (int) Syscall.pread (fd, pb, (ulong) buf.Length, offset);
|
||||
}
|
||||
});
|
||||
bytesRead = br;
|
||||
return e;
|
||||
}
|
||||
|
||||
protected override unsafe Errno OnWriteHandle (string path, OpenedPathInfo info,
|
||||
byte[] buf, long offset, out int bytesWritten)
|
||||
{
|
||||
int bw = 0;
|
||||
Errno e = ProcessFile (basedir+path, OpenFlags.O_WRONLY, delegate (int fd) {
|
||||
fixed (byte *pb = buf) {
|
||||
return bw = (int) Syscall.pwrite (fd, pb, (ulong) buf.Length, offset);
|
||||
}
|
||||
});
|
||||
bytesWritten = bw;
|
||||
return e;
|
||||
}
|
||||
|
||||
protected override Errno OnGetFileSystemStatus (string path, out Statvfs stbuf)
|
||||
{
|
||||
int r = Syscall.statvfs (basedir+path, out stbuf);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnReleaseHandle (string path, OpenedPathInfo info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnSynchronizeHandle (string path, OpenedPathInfo info, bool onlyUserData)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnSetPathExtendedAttribute (string path, string name, byte[] value, XattrFlags flags)
|
||||
{
|
||||
int r = Syscall.lsetxattr (basedir+path, name, value, (ulong) value.Length, flags);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnGetPathExtendedAttribute (string path, string name, byte[] value, out int bytesWritten)
|
||||
{
|
||||
int r = bytesWritten = (int) Syscall.lgetxattr (basedir+path, name, value, (ulong) value.Length);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnListPathExtendedAttributes (string path, out string[] names)
|
||||
{
|
||||
int r = (int) Syscall.llistxattr (basedir+path, out names);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnRemovePathExtendedAttribute (string path, string name)
|
||||
{
|
||||
int r = Syscall.lremovexattr (basedir+path, name);
|
||||
if (r == -1)
|
||||
return Stdlib.GetLastError ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override Errno OnLockHandle (string file, OpenedPathInfo info, FcntlCommand cmd, ref Flock @lock)
|
||||
{
|
||||
Flock _lock = @lock;
|
||||
Errno e = ProcessFile (basedir+file, info.OpenFlags, fd => Syscall.fcntl (fd, cmd, ref _lock));
|
||||
@lock = _lock;
|
||||
return e;
|
||||
}
|
||||
|
||||
private bool ParseArguments (string[] args)
|
||||
{
|
||||
for (int i = 0; i < args.Length; ++i) {
|
||||
switch (args [i]) {
|
||||
case "-h":
|
||||
case "--help":
|
||||
ShowHelp ();
|
||||
return false;
|
||||
default:
|
||||
if (base.MountPoint == null)
|
||||
base.MountPoint = args [i];
|
||||
else
|
||||
basedir = args [i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (base.MountPoint == null) {
|
||||
return Error ("missing mountpoint");
|
||||
}
|
||||
if (basedir == null) {
|
||||
return Error ("missing basedir");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void ShowHelp ()
|
||||
{
|
||||
Console.Error.WriteLine ("usage: redirectfs [options] mountpoint basedir:");
|
||||
FileSystem.ShowFuseHelp ("redirectfs");
|
||||
Console.Error.WriteLine ();
|
||||
Console.Error.WriteLine ("redirectfs options:");
|
||||
Console.Error.WriteLine (" basedir Directory to mirror");
|
||||
}
|
||||
|
||||
private static bool Error (string message)
|
||||
{
|
||||
Console.Error.WriteLine ("redirectfs: error: {0}", message);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Main (string[] args)
|
||||
{
|
||||
using (RedirectFS fs = new RedirectFS ()) {
|
||||
string[] unhandled = fs.ParseFuseArguments (args);
|
||||
if (!fs.ParseArguments (unhandled))
|
||||
return;
|
||||
fs.Start ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
example/RedirectFS/RedirectFS.csproj
Normal file
19
example/RedirectFS/RedirectFS.csproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Mono.Fuse.NETStandard.Samples</RootNamespace>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Mono.Fuse.NETStandard\Mono.Fuse.NETStandard.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0-beta3" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user