This repository has been archived on 2025-05-24. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Mono.Fuse.NETStandard/example/RedirectFS-FH/RedirectFS-FH.cs

422 lines
11 KiB
C#

//
// 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 ?? 0));
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 ();
}
}
}
}