├── Imagery
└── Snarf_by_stanlydan.png
├── .gitmodules
├── Application
├── App.config
├── Nfs
│ ├── NFSException.cs
│ ├── FileSystem
│ │ ├── FileSystemInfo.cs
│ │ ├── Enums.cs
│ │ ├── FileHandle.cs
│ │ ├── NfsIO.cs
│ │ ├── NfsFileAttributes.cs
│ │ └── NfsDirectory.cs
│ ├── NfsListenerManager.cs
│ ├── NfsHandlerManager.cs
│ ├── NfsPath.cs
│ ├── Enums.cs
│ ├── HandleManager.cs
│ ├── MountManager.cs
│ ├── NfsPacket.cs
│ ├── NfsTime.cs
│ ├── BaseHandler.cs
│ ├── NfsHandler.cs
│ ├── MountHandler.cs
│ └── PortmapHandler.cs
├── Program.cs
├── Extensions.cs
├── Udp
│ ├── DatagramPacket.cs
│ ├── UdpPacket.cs
│ ├── UdpHandler.cs
│ └── UdpListener.cs
├── Properties
│ └── AssemblyInfo.cs
├── Snarf.sln
└── Snarf.csproj
├── COPYRIGHTS.md
├── LICENSE
├── README.md
└── .gitignore
/Imagery/Snarf_by_stanlydan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shellscape/Snarf/HEAD/Imagery/Snarf_by_stanlydan.png
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "External/Shellscape.Common"]
2 | path = External/Shellscape.Common
3 | url = git@github.com:shellscape/Shellscape.Common.git
4 |
--------------------------------------------------------------------------------
/Application/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Application/Nfs/NFSException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Snarf.Nfs {
4 | public class NFSException : Exception {
5 |
6 | internal NFSException(uint xId, uint errorNumber) {
7 | XID = xId;
8 | ErrorNumber = errorNumber;
9 | }
10 |
11 | public uint XID { get; private set; }
12 | public uint ErrorNumber { get; private set; }
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/COPYRIGHTS.md:
--------------------------------------------------------------------------------
1 | Copyright Info
2 | ==============
3 |
4 | **Snarf_by_stanlydan.png**
5 |
6 | Derivative work based on 'Snarf' by DanielMead
7 |
8 | * Original URL - http://danielmead.deviantart.com/art/Snarf-95875488
9 | * Author's Website - http://danielmead.deviantart.com/
10 |
11 | I attempted to obtain permission to use the original piece but could not get a definitive 'yes' or 'no' answer. Should the author request removal, I'll comply immediately.
--------------------------------------------------------------------------------
/Application/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | using Snarf.Udp;
8 | using Snarf.Nfs;
9 |
10 | namespace Snarf {
11 | class Program {
12 | static void Main(string[] args) {
13 |
14 | MountManager.Init();
15 | HandleManager.Init();
16 |
17 | var nfs = new NfsHandler();
18 | var mount = new MountHandler();
19 | var portmap = new PortmapHandler();
20 |
21 | nfs.Start();
22 | mount.Start();
23 | portmap.Start();
24 |
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Application/Nfs/FileSystem/FileSystemInfo.cs:
--------------------------------------------------------------------------------
1 | // this class is used to encapsulate all of the file system information. The
2 | // idea is that it be replaced by native code to get better NFS behavior.
3 | namespace Snarf.Nfs.FileSystem {
4 |
5 | ///
6 | /// Used to encapsulate all of the file system information. The idea is that it be replaced by native code to get better NFS behavior.
7 | ///
8 | public class FileSystemInfo {
9 |
10 | internal FileSystemInfo() {
11 | }
12 |
13 | internal virtual void SetFS(string path) {
14 | }
15 |
16 | internal virtual uint TransferSize { get { return 8192; } }
17 | internal virtual uint BlockSize { get { return 512; } }
18 | internal virtual uint TotalBlocks { get { return 0; } }
19 | internal virtual uint FreeBlocks { get { return 0; } }
20 | internal virtual uint AvailableBlocks { get { return 0; } }
21 | }
22 | }
--------------------------------------------------------------------------------
/Application/Nfs/NfsListenerManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | using Snarf.Udp;
8 |
9 | namespace Snarf.Nfs {
10 |
11 | public static class NfsListenerManager {
12 |
13 | private static List> _cache;
14 |
15 | static NfsListenerManager() {
16 | _cache = new List>();
17 | }
18 |
19 | public static UdpListener GetListener(int port, int programId) {
20 | var tuple = _cache.Where(o => o.Item1 == port).FirstOrDefault();
21 | UdpListener listener = null;
22 |
23 | if (tuple == null) {
24 | listener = new UdpListener(port, false);
25 | listener.Start();
26 |
27 | _cache.Add(new Tuple(port, programId, listener));
28 | }
29 | else {
30 | listener = tuple.Item3;
31 | }
32 | return listener;
33 | }
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Application/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Snarf {
9 | public static class Extensions {
10 |
11 | public static Boolean Is(this FileAttributes attributes, FileAttributes value) {
12 | return ((attributes & value) == value);
13 | }
14 |
15 | public static void BubbleSort(this IList list) {
16 | BubbleSort(list, Comparer.Default);
17 | }
18 |
19 | private static void BubbleSort(IList list, IComparer comparer) {
20 | bool stillGoing = true;
21 | while (stillGoing) {
22 | stillGoing = false;
23 | for (int i = 0; i < list.Count - 1; i++) {
24 | T x = list[i];
25 | T y = list[i + 1];
26 | if (comparer.Compare(x, y) > 0) {
27 | list[i] = y;
28 | list[i + 1] = x;
29 | stillGoing = true;
30 | }
31 | }
32 | }
33 | }
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Application/Udp/DatagramPacket.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Net;
6 |
7 | namespace Snarf.Udp {
8 | public class DatagramPacket {
9 | private byte[] _bytes;
10 | private int _length;
11 | private IPEndPoint _endPoint;
12 |
13 | public DatagramPacket(byte[] bytes, int length, IPEndPoint endPoint) : this(bytes, length) {
14 | _endPoint = endPoint;
15 | }
16 |
17 | public DatagramPacket(byte[] bytes, int length) {
18 | _length = length;
19 | _bytes = new byte[_length];
20 | Buffer.BlockCopy(bytes, 0, _bytes, 0, _length);
21 | }
22 |
23 | public byte[] Bytes {
24 | get { return _bytes; }
25 | set {
26 | _bytes = value;
27 | _length = value.Length;
28 | }
29 | }
30 |
31 | public int Length {
32 | get { return _length; }
33 | }
34 |
35 | public IPEndPoint ServerEndPoint {
36 | get { return _endPoint; }
37 | set { _endPoint = value; }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Application/Nfs/NfsHandlerManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Snarf.Nfs {
8 | public static class NfsHandlerManager {
9 |
10 | private static List _cache;
11 |
12 | static NfsHandlerManager() {
13 | _cache = new List();
14 | }
15 |
16 | public static void RegisterHandler(BaseHandler handler) {
17 | if (_cache.Contains(handler)) {
18 | throw new Exception("Handler has already been registered");
19 | }
20 | _cache.Add(handler);
21 | }
22 |
23 | public static int GetPort(int programId) {
24 | var handler = _cache.Where(o => o.ProgramID == programId).FirstOrDefault();
25 |
26 | if (handler != null) {
27 | return handler.Port;
28 | }
29 | return 0;
30 | }
31 |
32 | public static Boolean IsProgramRegistered(int programId) {
33 | var handler = _cache.Where(o => o.ProgramID == programId).FirstOrDefault();
34 | return handler != null;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2011 Andrew Powell, Shellscape Software
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/Application/Nfs/NfsPath.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Snarf.Nfs {
9 | public static class NfsPath {
10 |
11 | public static String ToWin(string unixPath) {
12 |
13 | String[] parts = unixPath.Split(new char[] { Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
14 | StringBuilder result = new StringBuilder();
15 |
16 | foreach (var part in parts) {
17 | result.Append(part);
18 | if (part == parts[0] && !part.Contains(Path.VolumeSeparatorChar)) {
19 | result.Append(Path.VolumeSeparatorChar);
20 | }
21 | result.Append(Path.DirectorySeparatorChar);
22 | }
23 |
24 | return result.ToString();
25 | }
26 |
27 | public static String ToUnix(string windowsPath) {
28 |
29 | String[] parts = windowsPath.Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
30 | StringBuilder result = new StringBuilder();
31 |
32 | foreach (var part in parts) {
33 | result.Append(part);
34 | if (part == parts[0] && !part.Contains(Path.VolumeSeparatorChar)) {
35 | result.Append(Path.VolumeSeparatorChar);
36 | }
37 | result.Append(Path.AltDirectorySeparatorChar);
38 | }
39 |
40 | return result.ToString();
41 | }
42 |
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Snarf
2 | =====
3 |
4 | Snarf is an NFS v2 server implementation written in C# with .NET 4.5.
5 |
6 | Snarf is based in part on the JNFS project by Steven Procter @ http://void.org/~steven/jnfs/.
7 |
8 | **Current Status**
9 |
10 | 11/18/2012
11 |
12 | - Mounts now list files and directories.
13 | - ~~Mounts can't cd into subdirectories for some reason. Still looking into this one.~~ Mounts can cd into subdirectories and ls.
14 | - File handles and mounts are now cached in file, server can be restarted without creating mount problems.
15 | - Opening files on the client works.
16 | - Saving on the client system doesn't work.
17 |
18 | 11/16/2012
19 |
20 | - First commit/push. The server accepts version 2 connections and mounts.
21 | - Mounts only list files and not directories.
22 | - Mounts cannot persist between server restarts.
23 | - Exports are not hooked up. If the client specifies a path that is valid, it is allowed. This is temporary.
24 |
25 | **But, Why?**
26 |
27 | I started writing this for my XBMC-AppleTV2 setup. After upgrading to Windows 8 on the machine my movies are connected to, SMB started to get flaky. Very flaky. I gave HaneWin NFS a shot (and a few others, FreeNFS and winnfsd) and wasn't satisfied with them.
28 |
29 | **Down the Road**
30 |
31 | - Implement the v3 spec over TCP.
32 |
33 | **Licensing**
34 |
35 | Unless otherwise stated, the code here is licensed under the MIT license. Have at it!
--------------------------------------------------------------------------------
/Application/Nfs/FileSystem/Enums.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Snarf.Nfs.FileSystem {
8 |
9 | public enum FileType : int {
10 | NFNON = 0,
11 | NFREG = 1,
12 | NFDIR = 2,
13 | NFBLK = 3,
14 | NFCHR = 4,
15 | NFLNK = 5
16 | }
17 |
18 | public enum FilePermissions : uint {
19 | UPDIR = 0040000, // This is a directory
20 | UPCHRS = 0020000, // This is a character special file
21 | UPBLKS = 0060000, // This is a block special file
22 | UPFILE = 0100000, // This is a regular file
23 | UPSLINK = 0120000, // This is a symbolic link file
24 | UPSOCK = 0140000, // This is a named socket
25 | UPSUID = 0004000, // Set user id on execution.
26 | UPSGID = 0002000, // Set group id on execution.
27 | UPSTICKY = 0001000, // Save swapped text even after use.
28 | UP_OREAD = 0000400, // Read permission for owner.
29 | UP_OWRITE = 0000200, // Write permission for owner.
30 | UP_OEXEC = 0000100, // Execute and search permission owner.
31 | UP_GREAD = 0000040, // Read permission for group.
32 | UP_GWRITE = 0000020, // Write permission for group.
33 | UP_GEXEC = 0000010, // Execute and search permission group.
34 | UP_WREAD = 0000004, // Read permission for world.
35 | UP_WWRITE = 0000002, // Write permission for world.
36 | UP_WEXEC = 0000001 // Execute and search permission world.
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/Application/Nfs/Enums.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Snarf.Nfs {
8 |
9 | public enum RpcSignalType : int {
10 | Call = 0,
11 | Reply = 1
12 | }
13 |
14 | public enum RpcMessageResult : int {
15 | Accepted = 0,
16 | Denied = 0
17 | }
18 |
19 | public enum RpcProcedure : int {
20 | Success = 0,
21 | ProgramUnavailable = 1,
22 | ProgramMismatch = 2,
23 | ProcedureUnavail = 3,
24 | GarbageArguments = 4
25 | }
26 |
27 | public enum RpcAuthFlavor : int {
28 | NULL = 0,
29 | UNIX = 1,
30 | SHORT = 2,
31 | DES = 3
32 | };
33 |
34 |
35 | public enum NfsProcedure : int {
36 | NULL = 0,
37 | GETATTR = 1,
38 | SETATTR = 2,
39 | ROOT = 3,
40 | LOOKUP = 4,
41 | READLINK = 5,
42 | READ = 6,
43 | WRITECACHE = 7,
44 | WRITE = 8,
45 | CREATE = 9,
46 | REMOVE = 10,
47 | RENAME = 11,
48 | LINK = 12,
49 | SYMLINK = 13,
50 | MKDIR = 14,
51 | RMDIR = 15,
52 | READDIR = 16,
53 | STATFS = 17
54 | }
55 |
56 | public enum NfsReply : int {
57 | OK = 0,
58 | ERR_PERM = 1,
59 | ERR_NOENT = 2,
60 | ERR_IO = 5,
61 | ERR_NXIO = 6,
62 | ERR_ACCES = 13,
63 | ERR_EXIST = 17,
64 | ERR_NODEV = 19,
65 | ERR_NOTDIR = 20,
66 | ERR_ISDIR = 21,
67 | ERR_FBIG = 27,
68 | ERR_NOSPC = 28,
69 | ERR_ROFS = 30,
70 | ERR_NAMETOOLONG = 63,
71 | ERR_NOTEMPTY = 66,
72 | ERR_DQUOT = 69,
73 | ERR_STALE = 70,
74 | ERR_WFLUSH = 99
75 | }
76 |
77 | public enum RpcPrototcol : int {
78 | TCP = 6,
79 | UDP = 17
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/Application/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Snarf")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Shellscape Software")]
12 | [assembly: AssemblyProduct("Snarf NFS Server")]
13 | [assembly: AssemblyCopyright("Copyright © 2012 Andrew Powell, Shellscape Software")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("37d04bfb-69f6-47b9-98db-d0ad8805aaa1")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Application/Nfs/HandleManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.CompilerServices;
5 | using System.Runtime.Serialization;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Snarf.Nfs {
10 |
11 | [DataContract(Name = "apphandles")]
12 | public class HandleManager : Shellscape.Configuration.Config {
13 |
14 | private object _lock = new object();
15 | private List _handles = new List() { null };
16 |
17 | [DataMember(Name="handles")]
18 | public List Handles {
19 | get { return _handles; }
20 | set { _handles = value; }
21 | }
22 |
23 | public uint GetHandle(String name) {
24 | lock (_lock) {
25 | if (_handles.Contains(name)) {
26 | uint handle = (uint)_handles.IndexOf(name);
27 | //Console.WriteLine("HandleManager.GetHandle: name: " + name + ", handle: " + handle);
28 | return handle;
29 | }
30 | var handleId = _handles.Count;
31 | _handles.Add(name);
32 | this.Save();
33 |
34 | return (uint)handleId;
35 | }
36 | }
37 |
38 | public String GetName(uint handleId) {
39 | lock (_lock) {
40 | if (_handles.Count >= handleId) {
41 | return _handles[(int)handleId];
42 | }
43 | throw new Exception("HandleManager.GetName: handleId not found.");
44 | }
45 | }
46 |
47 | protected override string ApplicationName {
48 | get { return Shellscape.Utilities.AssemblyMeta.AssemblyName; }
49 | }
50 |
51 | protected override void SetDefaults() {
52 | _lock = new object();
53 | this.FileName = "app.handles";
54 | #if DEBUG
55 | this.AppDataPath = this.StorePath = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath);
56 | #endif
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/Application/Nfs/MountManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.CompilerServices;
5 | using System.Runtime.Serialization;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Snarf.Nfs {
10 |
11 | public class Mount {
12 |
13 | public String ClientID { get; set; }
14 | public String MountPoint { get; set; }
15 |
16 | }
17 |
18 | [DataContract(Name = "appmounts")]
19 | public class MountManager : Shellscape.Configuration.Config {
20 |
21 | private object _lock = new object();
22 | private List _mounts = new List();
23 |
24 | [DataMember(Name="mounts")]
25 | public List Mounts {
26 | get { return _mounts; }
27 | set { _mounts = value; }
28 | }
29 |
30 | public Boolean Add(String clientId, String mountPoint) {
31 | var mount = _mounts.Where(o => o.ClientID == clientId && o.MountPoint == mountPoint).FirstOrDefault();
32 | if (mount != null) {
33 | return false;
34 | }
35 | _mounts.Add(new Mount() { ClientID = clientId, MountPoint = mountPoint });
36 | this.Save();
37 | return true;
38 | }
39 |
40 | public Boolean Remove(String clientId) {
41 | var mount = _mounts.Where(o => o.ClientID == clientId).FirstOrDefault();
42 | if (mount != null && _mounts.Contains(mount)) {
43 | _mounts.Remove(mount);
44 | this.Save();
45 | }
46 | else {
47 | return false;
48 | //throw new Exception("MountManager.Remove: mount(" + clientId + ") not found.");
49 | }
50 | return true;
51 | }
52 |
53 | protected override string ApplicationName {
54 | get { return Shellscape.Utilities.AssemblyMeta.AssemblyName; }
55 | }
56 |
57 | protected override void SetDefaults() {
58 | _lock = new object();
59 | this.FileName = "app.mounts";
60 | #if DEBUG
61 | this.AppDataPath = this.StorePath = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath);
62 | #endif
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
2 | [Bb]in/
3 | [Oo]bj/
4 |
5 | # mstest test results
6 | TestResults
7 |
8 | ## Ignore Visual Studio temporary files, build results, and
9 | ## files generated by popular Visual Studio add-ons.
10 |
11 | # User-specific files
12 | *.suo
13 | *.user
14 | *.sln.docstates
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Rr]elease/
19 | x64/
20 | *_i.c
21 | *_p.c
22 | *.ilk
23 | *.meta
24 | *.obj
25 | *.pch
26 | *.pdb
27 | *.pgc
28 | *.pgd
29 | *.rsp
30 | *.sbr
31 | *.tlb
32 | *.tli
33 | *.tlh
34 | *.tmp
35 | *.log
36 | *.vspscc
37 | *.vssscc
38 | .builds
39 |
40 | # Visual C++ cache files
41 | ipch/
42 | *.aps
43 | *.ncb
44 | *.opensdf
45 | *.sdf
46 |
47 | # Visual Studio profiler
48 | *.psess
49 | *.vsp
50 | *.vspx
51 |
52 | # Guidance Automation Toolkit
53 | *.gpState
54 |
55 | # ReSharper is a .NET coding add-in
56 | _ReSharper*
57 |
58 | # NCrunch
59 | *.ncrunch*
60 | .*crunch*.local.xml
61 |
62 | # Installshield output folder
63 | [Ee]xpress
64 |
65 | # DocProject is a documentation generator add-in
66 | DocProject/buildhelp/
67 | DocProject/Help/*.HxT
68 | DocProject/Help/*.HxC
69 | DocProject/Help/*.hhc
70 | DocProject/Help/*.hhk
71 | DocProject/Help/*.hhp
72 | DocProject/Help/Html2
73 | DocProject/Help/html
74 |
75 | # Click-Once directory
76 | publish
77 |
78 | # Publish Web Output
79 | *.Publish.xml
80 |
81 | # NuGet Packages Directory
82 | packages
83 |
84 | # Windows Azure Build Output
85 | csx
86 | *.build.csdef
87 |
88 | # Windows Store app package directory
89 | AppPackages/
90 |
91 | # Others
92 | [Bb]in
93 | [Oo]bj
94 | sql
95 | TestResults
96 | [Tt]est[Rr]esult*
97 | *.Cache
98 | ClientBin
99 | [Ss]tyle[Cc]op.*
100 | ~$*
101 | *.dbmdl
102 | Generated_Code #added for RIA/Silverlight projects
103 |
104 | # Backup & report files from converting an old project file to a newer
105 | # Visual Studio version. Backup files are not needed, because we have git ;-)
106 | _UpgradeReport_Files/
107 | Backup*/
108 | UpgradeLog*.XML
109 |
--------------------------------------------------------------------------------
/Application/Nfs/NfsPacket.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | using Snarf.Udp;
8 |
9 | namespace Snarf.Nfs {
10 |
11 | public class NfsPacket : UdpPacket {
12 |
13 | public NfsPacket(DatagramPacket datagram) : base(datagram) { }
14 |
15 | public NfsPacket(int size) : base(size) { }
16 |
17 | public uint XID { get; set; }
18 | public uint RpcVersion { get; set; }
19 | public uint ProgramID { get; set; }
20 | public uint NfsVersion { get; set; }
21 | public uint ProcedureID { get; set; }
22 |
23 | public String RemoteHost { get; set; }
24 |
25 | // struct auth_unix - RFC 1057- page 12
26 | //private uint AuthStamp { get; set; }
27 | //public String AuthMachineName { get; set; }
28 | //public uint AuthClientID { get; set; }
29 |
30 | public virtual void AddReplyHeader(uint xid) {
31 | SetUInt(xid);
32 | SetUInt((uint)RpcSignalType.Reply);
33 | SetUInt((uint)RpcMessageResult.Accepted);
34 | AddNullAuthentication();
35 | SetUInt((uint)RpcProcedure.Success);
36 | }
37 |
38 | public virtual void AddNullAuthentication() {
39 | SetUInt(0); // the type
40 | SetUInt(0); // the length
41 | }
42 |
43 | public virtual void ReadAuthentication() {
44 | uint type = GetUInt();
45 | uint length = GetUInt();
46 | //int startPos = this.Position; // know where we started before we got the info we need, so we can skip ahead.
47 |
48 | //if (type == (uint)RpcAuthFlavor.UNIX) {
49 | // AuthStamp = GetUInt();
50 | // AuthMachineName = GetString();
51 | // AuthClientID = GetUInt();
52 |
53 | // // skip the gids portion
54 | // int advance = (int)length - (this.Position - startPos);
55 | // if (advance > 0) {
56 | // Advance((uint)advance);
57 | // }
58 | //}
59 | //else {
60 | Advance(length);
61 | //}
62 |
63 | //struct auth_unix {
64 | // unsigned int stamp;
65 | // string machinename<255>;
66 | // unsigned int uid;
67 | // unsigned int gid;
68 | // unsigned int gids<16>;
69 | //}
70 | }
71 |
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Application/Snarf.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Snarf", "Snarf.csproj", "{A74404F2-5664-4C75-BB06-0D1BB0292B60}"
5 | EndProject
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{24F6E643-0126-4DA9-B2C2-4C7B5983EE9D}"
7 | ProjectSection(SolutionItems) = preProject
8 | ..\COPYRIGHTS.md = ..\COPYRIGHTS.md
9 | ..\LICENSE = ..\LICENSE
10 | ..\README.md = ..\README.md
11 | EndProjectSection
12 | EndProject
13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shellscape.Common", "..\External\Shellscape.Common\Shellscape.Common\Shellscape.Common.csproj", "{F7F1F64D-F6CD-42A9-B167-546E4EA31463}"
14 | EndProject
15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Windows API", "..\External\Shellscape.Common\Microsoft\Windows API\Windows API.csproj", "{B20A1853-BDC5-47D5-9369-3999BBD7F516}"
16 | EndProject
17 | Global
18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
19 | Debug|Any CPU = Debug|Any CPU
20 | Release|Any CPU = Release|Any CPU
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {A74404F2-5664-4C75-BB06-0D1BB0292B60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {A74404F2-5664-4C75-BB06-0D1BB0292B60}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {A74404F2-5664-4C75-BB06-0D1BB0292B60}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {A74404F2-5664-4C75-BB06-0D1BB0292B60}.Release|Any CPU.Build.0 = Release|Any CPU
27 | {F7F1F64D-F6CD-42A9-B167-546E4EA31463}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {F7F1F64D-F6CD-42A9-B167-546E4EA31463}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {F7F1F64D-F6CD-42A9-B167-546E4EA31463}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {F7F1F64D-F6CD-42A9-B167-546E4EA31463}.Release|Any CPU.Build.0 = Release|Any CPU
31 | {B20A1853-BDC5-47D5-9369-3999BBD7F516}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {B20A1853-BDC5-47D5-9369-3999BBD7F516}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {B20A1853-BDC5-47D5-9369-3999BBD7F516}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 | {B20A1853-BDC5-47D5-9369-3999BBD7F516}.Release|Any CPU.Build.0 = Release|Any CPU
35 | EndGlobalSection
36 | GlobalSection(SolutionProperties) = preSolution
37 | HideSolutionNode = FALSE
38 | EndGlobalSection
39 | EndGlobal
40 |
--------------------------------------------------------------------------------
/Application/Nfs/FileSystem/FileHandle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | //
8 | // The FileHandle is used by NFS to represent files. It is a 32 byte piece of data that the NFS client gets from mountd or the NFS
9 | // server.
10 | //
11 | // This implementation stores 3 things in the FileHandle: the handle of the root of this file system (the handle of the mount point),
12 | // the handle of the file, and a flag indicating whether this handle is read only. The rest of the 32 bytes are not used, but since
13 | // NFS clients think two files are the same iff the FileHandles are the same, make sure this always gives out the same FileHandle by
14 | // setting the rest of the data to 0.
15 |
16 |
17 | namespace Snarf.Nfs.FileSystem {
18 | public class FileHandle {
19 |
20 | internal uint root; // handle of the root of this mount point
21 | internal uint handle; // handle of the file
22 | internal uint @readonly; // is the mount read only?
23 |
24 | public FileHandle() {
25 | }
26 |
27 | // Initialize this FileHandle from the packet, leave the position in the packet just past the FileHandle.
28 | public FileHandle(NfsPacket source) {
29 | Read(source);
30 | }
31 |
32 | public virtual uint Root { get { return root; } }
33 |
34 | public virtual uint Handle { get { return handle; } }
35 |
36 | public virtual uint ReadOnly { get { return @readonly; } }
37 |
38 | internal virtual bool Read(NfsPacket packet) {
39 |
40 | root = packet.GetUInt(); // the first long in the packet is the handle of the root
41 | handle = packet.GetUInt(); // the next long is the handle of the file
42 | @readonly = packet.GetUInt(); // the next is a read only flag
43 |
44 | // The rest is nothing. There are 32 bytes in a FileHandle and this has read in 3 words, or 12 bytes.
45 | packet.Advance(32 - 3 * 4);
46 |
47 | return true;
48 | }
49 |
50 | public Boolean Set(uint root, uint handle, uint readOnly) {
51 | this.root = root;
52 | this.handle = handle;
53 | this.@readonly = readOnly;
54 |
55 | return true;
56 | }
57 |
58 | public Boolean Emit(ref NfsPacket packet) {
59 | packet.SetUInt(root);
60 | packet.SetUInt(handle);
61 | packet.SetUInt(@readonly);
62 |
63 | // The rest of the words of the handle should be 0. Since there are 32 bytes in a handle,
64 | // there are 8 words and the above consumed 3 of them, so there are 5 left.
65 | for (int i = 0; i < 5; i++) {
66 | packet.SetUInt(0);
67 | }
68 |
69 | return true;
70 | }
71 |
72 | //internal virtual void Print() {
73 | // Console.WriteLine("FileHandle: root: " + root + ", handle: " + handle + ", readonly: " + @readonly);
74 | //}
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Application/Nfs/NfsTime.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Snarf.Nfs {
4 | public class NfsTime {
5 |
6 | private uint _seconds;
7 | private uint _milliseconds;
8 | private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
9 |
10 | public NfsTime(NfsPacket packet) {
11 | Read(packet);
12 | }
13 |
14 | public NfsTime(uint seconds, uint milliseconds) {
15 | Set(seconds, milliseconds);
16 | }
17 |
18 | public NfsTime(DateTime dateTime) {
19 | Set(GetSeconds(dateTime), GetMilliseconds(dateTime));
20 | }
21 |
22 | public NfsTime(uint time) {
23 | // convert a 64 bit uint into two 32 bit uints to pass to the regular set function
24 | uint top = time >> 16;
25 | uint bottom = time & 0xffff;
26 |
27 | bottom += (top & 0xffff) << 16;
28 | top = top >> 16;
29 |
30 | Set(top, bottom);
31 | }
32 |
33 | internal virtual bool Read(NfsPacket packet) {
34 | _seconds = packet.GetUInt();
35 | _milliseconds = packet.GetUInt();
36 | return true;
37 | }
38 |
39 | internal virtual bool Emit(ref NfsPacket packet) {
40 | packet.SetUInt(_seconds);
41 | packet.SetUInt(_milliseconds);
42 | return true;
43 | }
44 |
45 | internal virtual bool Set(uint seconds, uint milliseconds) {
46 | _seconds = seconds;
47 | _milliseconds = milliseconds;
48 | return true;
49 | }
50 |
51 | internal virtual void Print() {
52 | Console.Write("Timeval: sec=" + _seconds + " msec=" + _milliseconds + "\n");
53 | }
54 |
55 | //public static uint GetSeconds(uint localTime) {
56 | // uint startTime = 27111902 << 32 + 54590 << 16 + 32768;
57 | // uint delta = localTime - startTime;
58 | // delta /= 1000;
59 | // return delta;
60 | //}
61 |
62 | //public static uint GetMilliSeconds(uint localTime) {
63 | // uint startTime = 27111902 << 32 + 54590 << 16 + 32768;
64 | // uint delta = localTime - startTime;
65 | // delta %= 1000;
66 | // return delta;
67 | //}
68 |
69 | //public static uint GetSeconds(uint localTime) {
70 | // return localTime / (1 << 32);
71 | //}
72 |
73 | //public static uint GetMilliSeconds(uint localTime) {
74 | // return localTime % (1 << 32);
75 | //}
76 |
77 |
78 | ///
79 | /// Returns the UNIX Timestamp value
80 | ///
81 | ///
82 | ///
83 | public static uint GetMilliseconds(DateTime dateTime) {
84 | return (uint)(dateTime.ToUniversalTime() - UnixEpoch).Milliseconds;
85 | }
86 |
87 | ///
88 | /// Returns the UNIX Timestamp value
89 | ///
90 | ///
91 | ///
92 | public static uint GetSeconds(DateTime dateTime) {
93 | return (uint)(dateTime.ToUniversalTime() - UnixEpoch).TotalSeconds;
94 | }
95 | }
96 | }
--------------------------------------------------------------------------------
/Application/Nfs/BaseHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | using Snarf.Udp;
9 |
10 | namespace Snarf.Nfs {
11 | public class BaseHandler : UdpHandler {
12 |
13 | public BaseHandler(int port, int programId) : base() {
14 |
15 | this.ProgramID = programId;
16 |
17 | NfsHandlerManager.RegisterHandler(this);
18 |
19 | _listener = NfsListenerManager.GetListener(port, programId);
20 | _listener.PacketReceived += OnPacketReceived;
21 | }
22 |
23 | public int ProgramID { get; private set; }
24 |
25 | protected virtual void Process(NfsPacket packet, IPEndPoint receivedFrom) {
26 | //Console.WriteLine("NfsHandler.Process : recievedFrom: " + receivedFrom.ToString());
27 | }
28 |
29 | protected override void OnPacketReceived(byte[] bytes, IPEndPoint receivedFrom) {
30 | var datagram = new DatagramPacket(bytes, bytes.Length, receivedFrom);
31 | var packet = new NfsPacket(datagram);
32 | var e = new UdpPacketReceivedEventArgs(packet, receivedFrom);
33 |
34 | //Console.WriteLine("\nPacket Received : EndPoint: " + _listener.Client.Client.LocalEndPoint.ToString());
35 |
36 | uint xId = packet.XID = packet.GetUInt();
37 | uint type = packet.GetUInt();
38 |
39 | if (type == (int)RpcSignalType.Call) {
40 | Call(ref packet, xId);
41 | }
42 | else if (type == (int)RpcSignalType.Reply) {
43 | Reply(ref packet, xId);
44 | }
45 |
46 | //RaisePacketReceived(e);
47 |
48 | if (packet.ProgramID == this.ProgramID) {
49 | //Console.WriteLine("Found program: " + packet.ProgramID);
50 | Process(packet, receivedFrom);
51 | }
52 | }
53 |
54 | protected virtual void Call(ref NfsPacket packet, uint xId) {
55 | uint rpcVersion = packet.RpcVersion = packet.GetUInt();
56 | uint programId = packet.ProgramID = packet.GetUInt();
57 | uint version = packet.NfsVersion = packet.GetUInt();
58 | uint procedure = packet.ProcedureID = packet.GetUInt();
59 |
60 | IPHostEntry entry = Dns.GetHostEntry(packet.Source);
61 | String[] parts = entry.HostName.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
62 |
63 | if (parts.Length >= 0) {
64 | packet.RemoteHost = parts[0];
65 | }
66 |
67 | //if (programId == this.ProgramID) {
68 | // Console.WriteLine("\nCall: rpcVersion = " + rpcVersion + " programId = " + programId + " version = " + version + " procedure = " + procedure);
69 | //}
70 | }
71 |
72 | protected virtual void Reply(ref NfsPacket packet, uint xId) {
73 | //Console.WriteLine("Reply: I don't handle these");
74 | }
75 |
76 | protected void SendNull(NfsPacket sourcePacket, IPEndPoint receivedFrom) {
77 |
78 | NfsPacket packet = new NfsPacket(128);
79 |
80 | packet.AddReplyHeader(sourcePacket.XID);
81 |
82 | Send(packet, receivedFrom);
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/Application/Nfs/NfsHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | using Snarf.Udp;
9 |
10 | namespace Snarf.Nfs {
11 | public class NfsHandler : BaseHandler {
12 |
13 | public const int NFS_PORT = 2049;
14 | public const int NFS_VERSION = 2;
15 | public const int NFS_PROGRAMID = 100003;
16 |
17 | public const int NFS_TRUE = 1;
18 | public const int NFS_FALSE = 0;
19 |
20 | private FileSystem.NfsDirectory _directory = null;
21 | private FileSystem.NfsIO _io = null;
22 |
23 | public NfsHandler() : base(NfsHandler.NFS_PORT, NfsHandler.NFS_PROGRAMID) {
24 | // read directory support
25 | _directory = new FileSystem.NfsDirectory(new FileSystem.FileSystemInfo());
26 |
27 | // read and write
28 | _io = new FileSystem.NfsIO();
29 |
30 | }
31 |
32 | protected override void Process(NfsPacket packet, IPEndPoint receivedFrom) {
33 | //Console.WriteLine("NfsHandler.Process : recievedFrom: " + receivedFrom.ToString());
34 | //Console.WriteLine("NfsHandler.Process: Procedure -> " + packet.ProcedureID + ":" + ((NfsProcedure)packet.ProcedureID).ToString());
35 |
36 | // get rid of authentication recorde in packet, we don't use them
37 | packet.ReadAuthentication();
38 | packet.ReadAuthentication();
39 |
40 | if (packet.ProcedureID == (int)NfsProcedure.NULL) {
41 | base.SendNull(packet, receivedFrom);
42 | return;
43 | }
44 |
45 | NfsPacket result;
46 | uint xid = packet.XID;
47 |
48 | try {
49 | switch (packet.ProcedureID) {
50 | case (int)NfsProcedure.GETATTR:
51 | result = _directory.GetAttr(packet);
52 | break;
53 | case (int)NfsProcedure.SETATTR:
54 | result = _directory.SetAttr(xid, packet);
55 | break;
56 | case (int)NfsProcedure.LOOKUP:
57 | result = _directory.Lookup(packet);
58 | break;
59 | case (int)NfsProcedure.READ:
60 | result = _io.Read(packet);
61 | break;
62 | case (int)NfsProcedure.WRITE:
63 | result = _io.Write(xid, packet);
64 | break;
65 | case (int)NfsProcedure.CREATE:
66 | result = _directory.Create(xid, packet);
67 | break;
68 | case (int)NfsProcedure.REMOVE:
69 | result = _directory.Remove(xid, packet);
70 | break;
71 | case (int)NfsProcedure.RENAME:
72 | result = _directory.Rename(xid, packet);
73 | break;
74 | case (int)NfsProcedure.MKDIR:
75 | result = _directory.Mkdir(xid, packet);
76 | break;
77 | case (int)NfsProcedure.RMDIR:
78 | result = _directory.Rmdir(xid, packet);
79 | break;
80 | case (int)NfsProcedure.READDIR:
81 | result = _directory.ReadDirectory(packet);
82 | break;
83 | case (int)NfsProcedure.STATFS:
84 | result = _directory.StatFS(packet);
85 | break;
86 | default:
87 | Console.Error.WriteLine("Unsupported NFS procedure called (" + packet.ProcedureID + ") from " + receivedFrom.ToString() + "\n");
88 | throw new NFSException(packet.XID, (uint)NfsReply.ERR_IO);
89 | }
90 | }
91 | catch (NFSException e) {
92 | // make a reply packet that includes the error
93 | result = new NfsPacket(64);
94 | result.AddReplyHeader(packet.XID);
95 | result.SetUInt(e.ErrorNumber);
96 | }
97 |
98 | Send(result, receivedFrom);
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/Application/Nfs/FileSystem/NfsIO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace Snarf.Nfs.FileSystem {
5 |
6 | public class NfsIO {
7 |
8 | internal NfsIO() { }
9 |
10 | public NfsPacket Write(uint xid, NfsPacket packet) {
11 | string fileName = null;
12 |
13 | try {
14 | // read info out of packet
15 | FileHandle fh = new FileHandle(packet);
16 | uint beginoffset = packet.GetUInt();
17 | uint offset = packet.GetUInt();
18 | uint totalcount = packet.GetUInt();
19 | // next comes the data which is a uint of size and the bytes.
20 | uint datalen = packet.GetUInt();
21 | uint packetOffset = (uint)packet.Position;
22 | packet.Advance(datalen);
23 |
24 | // carry out the write operation
25 | fileName = HandleManager.Current.GetName(fh.Handle);
26 | if (fileName == null) {
27 | throw new NFSException(xid, (uint)NfsReply.ERR_STALE);
28 | }
29 | // XXX comment out print lines to improve performance
30 | // System.out.print("Write(" + fileName + ", " + offset + ", " +
31 | // datalen + ")\n");
32 | using (StreamWriter sw = new StreamWriter(fileName)) {
33 | sw.BaseStream.Seek(offset, SeekOrigin.Begin);
34 | sw.BaseStream.Write(packet.Data, (int)packetOffset, (int)datalen);
35 | }
36 |
37 | // load in new file attributes
38 | NfsFileAttributes fa = new NfsFileAttributes();
39 | fa.Load(fileName);
40 |
41 | // create the reply packet
42 | NfsPacket result = new NfsPacket(128);
43 | result.Reset();
44 | result.AddReplyHeader(xid);
45 | result.SetUInt((uint)NfsReply.OK);
46 | fa.Emit(ref result);
47 |
48 | return result;
49 | }
50 | catch (IOException) {
51 | throw new NFSException(xid, (uint)NfsReply.ERR_IO);
52 | }
53 | catch (System.Security.SecurityException) {
54 | throw new NFSException(xid, (uint)NfsReply.ERR_PERM);
55 | }
56 | }
57 |
58 | public NfsPacket Read(NfsPacket packet) {
59 | try {
60 | FileHandle fh = new FileHandle(packet);
61 | uint offset = packet.GetUInt();
62 | uint count = packet.GetUInt();
63 | uint totalCount = packet.GetUInt(); // not used
64 | uint xId = packet.XID;
65 | int numberRead;
66 | byte[] readbuf;
67 | String filePath = HandleManager.Current.GetName(fh.Handle);
68 |
69 | if (filePath == null) {
70 | throw new NFSException(xId, (uint)NfsReply.ERR_STALE);
71 | }
72 |
73 | if (count <= 0) {
74 | Console.Error.WriteLine("\tNfsIO.Read: invalid value for count " + count);
75 | throw new NFSException(xId, (uint)NfsReply.ERR_IO);
76 | }
77 |
78 | using (StreamReader sr = new StreamReader(filePath)) {
79 | sr.BaseStream.Seek(offset, SeekOrigin.Begin);
80 | readbuf = new byte[(int)count];
81 | numberRead = sr.BaseStream.Read(readbuf, 0, (int)count);
82 | }
83 |
84 | if (numberRead < 0) {
85 | Console.Error.WriteLine("\tNfsIO.Read: number read is " + numberRead);
86 | numberRead = 0;
87 | }
88 |
89 | NfsFileAttributes attributes = new NfsFileAttributes(filePath);
90 | NfsPacket reply = new NfsPacket(128 + numberRead);
91 |
92 | reply.AddReplyHeader(xId);
93 | reply.SetUInt((uint)NfsReply.OK);
94 |
95 | attributes.Emit(ref reply);
96 |
97 | reply.SetData(numberRead, readbuf);
98 |
99 | return reply;
100 | }
101 | catch (FileNotFoundException) {
102 | throw new NFSException(packet.XID, (uint)NfsReply.ERR_NOENT);
103 | }
104 | catch (IOException) {
105 | throw new NFSException(packet.XID, (uint)NfsReply.ERR_IO);
106 | }
107 | }
108 | }
109 |
110 | }
--------------------------------------------------------------------------------
/Application/Nfs/MountHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | using Snarf.Udp;
10 |
11 | namespace Snarf.Nfs {
12 |
13 | public class MountHandler : BaseHandler {
14 |
15 | public const int MOUNT_PORT = 2049; // mountd doesn't have assigned port
16 | public const int MOUNT_VERSION = 1;
17 | public const int MOUNT_PROGRAMID = 100005;
18 |
19 | public enum MountProcedure : int {
20 | NULL = 0,
21 | MNT = 1,
22 | UMNT = 3
23 | }
24 |
25 | public MountHandler() : base(MOUNT_PORT, MOUNT_PROGRAMID) { // system will set the port
26 |
27 | }
28 |
29 | protected override void Process(NfsPacket packet, IPEndPoint receivedFrom) {
30 | //Console.WriteLine("MountHandler.Process : recievedFrom: " + receivedFrom.ToString());
31 | //Console.WriteLine("MountHandler.Process: Procedure -> " + packet.ProcedureID + ":" + ((MountProcedure)packet.ProcedureID).ToString());
32 |
33 | switch (packet.ProcedureID) {
34 | case (int)MountProcedure.NULL:
35 | base.SendNull(packet, receivedFrom);
36 | break;
37 | case (int)MountProcedure.MNT:
38 | Mount(packet, receivedFrom);
39 | break;
40 | case (int)MountProcedure.UMNT:
41 | Unmount(packet, receivedFrom);
42 | break;
43 | default:
44 | break;
45 |
46 | }
47 | }
48 |
49 | private void Mount(NfsPacket sourcePacket, IPEndPoint receivedFrom) {
50 |
51 | NfsReply replyCode = NfsReply.OK;
52 | NfsPacket packet = new NfsPacket(128);
53 |
54 | packet.AddReplyHeader(sourcePacket.XID);
55 |
56 | // skip past the authentication records
57 | sourcePacket.ReadAuthentication();
58 | sourcePacket.ReadAuthentication();
59 |
60 | // next should be a dirpath, which is a string. Replace unix style path with local style path
61 | String path = sourcePacket.GetString();
62 |
63 | if (path == null) {
64 | replyCode = NfsReply.ERR_STALE;
65 | }
66 | else {
67 | String original = path.Clone() as String;
68 |
69 | path = NfsPath.ToWin(path);
70 |
71 | //Console.WriteLine("MountHandler.Mount : requested: " + original + ", actual: " + path);
72 |
73 | //if (!Directory.Exists(path)) {
74 | // replyCode = NfsReply.ERR_EXIST;
75 | //}
76 | }
77 |
78 | // Try to validate this mount, if there is an error make an error packet, otherwise send back the handle.
79 |
80 | if (replyCode != NfsReply.OK) {
81 | packet.SetUInt((uint)replyCode);
82 |
83 | }
84 | else if (false){ //exports.Matches(packet.Source(), path) == false) {
85 | // No permission for this mount in the exports file
86 | //result.AddLong(NFS.NFSERR_PERM);
87 | //Console.Error.WriteLine("!!! Mount request for " + path + "from " + packet.Source() + " denied.\n");
88 | }
89 | else {
90 | // put together a file handle
91 | uint handle = HandleManager.Current.GetHandle(path);
92 | var fileHandle = new FileSystem.FileHandle();
93 |
94 | fileHandle.Set(handle, (uint)handle, 0);
95 |
96 | packet.SetUInt((uint)replyCode);
97 |
98 | fileHandle.Emit(ref packet);
99 | }
100 |
101 | if (replyCode == NfsReply.OK) {
102 | MountManager.Current.Add(sourcePacket.RemoteHost, path);
103 | }
104 |
105 | Send(packet, receivedFrom);
106 | }
107 |
108 | private void Unmount(NfsPacket sourcePacket, IPEndPoint receivedFrom) {
109 |
110 | // skip past the authentication records
111 | sourcePacket.ReadAuthentication();
112 | sourcePacket.ReadAuthentication();
113 |
114 | String path = sourcePacket.GetString();
115 | NfsPacket packet = new NfsPacket(128);
116 |
117 | path = NfsPath.ToWin(path);
118 |
119 | HandleManager.Current.GetHandle(path);
120 |
121 | packet.AddReplyHeader(sourcePacket.XID);
122 | packet.SetUInt((uint)NfsReply.OK);
123 |
124 | //Console.WriteLine("MountHandler.Unmount : requested: " + path);
125 |
126 | MountManager.Current.Remove(sourcePacket.RemoteHost);
127 |
128 | Send(packet, receivedFrom);
129 | }
130 |
131 |
132 |
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/Application/Udp/UdpPacket.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Net.Sockets;
4 |
5 | namespace Snarf.Udp {
6 |
7 | public class UdpPacket {
8 |
9 | private byte[] _data;
10 | private int _length;
11 | private int _position;
12 |
13 | // store information about where the packet came from
14 | private IPAddress _source;
15 | private int _port;
16 |
17 | public UdpPacket(DatagramPacket datagram) {
18 | _data = datagram.Bytes;
19 | _length = datagram.Length;
20 | _position = 0;
21 | _source = datagram.ServerEndPoint == null ? null : datagram.ServerEndPoint.Address;
22 | _port = datagram.ServerEndPoint == null ? 0 : datagram.ServerEndPoint.Port;
23 |
24 | //Console.Write("source: " + _source);
25 | //Console.Write(" port: " + _port);
26 | //Console.Write(" data length: " + _length + "\n");
27 | }
28 |
29 | public UdpPacket(int size) {
30 | _length = size;
31 | _data = new byte[_length];
32 | _position = 0;
33 | }
34 |
35 | public byte[] Data { get { return _data; } }
36 |
37 | ///
38 | /// Returns the length of the data written to the buffer. This is sometimes different than Data.Length.
39 | ///
40 | public int Length { get { return _position; } }
41 | public int Position { get { return _position; } }
42 | public IPAddress Source { get { return _source; } }
43 | public int Port { get { return _port; } }
44 |
45 | #region . Get Methods .
46 |
47 | public uint GetUInt() {
48 |
49 | uint one = _data[_position];
50 | one <<= 24;
51 | uint two = _data[_position + 1];
52 | two <<= 16;
53 | uint three = _data[_position + 2];
54 | three <<= 8;
55 | uint four = _data[_position + 3];
56 |
57 | uint result = one | two | three | four;
58 |
59 | _position += 4;
60 |
61 | return result;
62 | }
63 |
64 | public long GetLong() {
65 |
66 | long one = _data[_position];
67 | one <<= 24;
68 | long two = _data[_position + 1];
69 | two <<= 16;
70 | long three = _data[_position + 2];
71 | three <<= 8;
72 | long four = _data[_position + 3];
73 |
74 | long result = one | two | three | four;
75 |
76 | _position += 4;
77 |
78 | return result;
79 | }
80 |
81 | public char GetChar() {
82 | char value = (char)_data[_position];
83 |
84 | ++_position;
85 |
86 | return value;
87 | }
88 |
89 | public String GetString() {
90 | uint length = GetUInt();
91 |
92 | String value = "";
93 |
94 | for (int charCount = 0; charCount < length; ++charCount) {
95 | value += GetChar();
96 | }
97 |
98 | if (length % 4 != 0) {
99 | _position += (int)(4 - length % 4);
100 | }
101 |
102 | return value;
103 | }
104 |
105 | public virtual long GetData(byte[] buffer) {
106 | uint plen = GetUInt(); // how much data is in the packet
107 | if (plen + _position >= _data.Length) {
108 | Console.Error.WriteLine("GetData: packet is too small\n");
109 | return -1;
110 | }
111 |
112 | // try to copy the data into the buffer
113 | Array.Copy(_data, _position, buffer, 0, (int)plen);
114 |
115 | Advance(plen);
116 | return plen;
117 | }
118 |
119 | #endregion
120 |
121 | #region . Set Methods .
122 |
123 | public void Set(int value) {
124 | SetUInt((uint)value);
125 | }
126 |
127 | public void SetUInt(uint value) {
128 | Need(4);
129 |
130 | uint one = value;
131 | uint two = value;
132 | two >>= 8;
133 | uint three = value;
134 | three >>= 16;
135 | uint four = value;
136 | four >>= 24;
137 |
138 | _data[_position] = (byte)four;
139 | _data[_position + 1] = (byte)three;
140 | _data[_position + 2] = (byte)two;
141 | _data[_position + 3] = (byte)one;
142 |
143 | _position += 4;
144 | }
145 |
146 | public void Set(String value) {
147 |
148 | Need(4 + value.Length + 3); // Extra in case of pad
149 |
150 | SetUInt((uint)value.Length);
151 |
152 | foreach (Char c in value) {
153 | _data[_position] = (byte)c;
154 | ++_position;
155 | }
156 |
157 | if (value.Length % 4 != 0) {
158 | for (int pad = 4 - value.Length % 4; pad != 0; --pad) {
159 | _data[_position] = 0;
160 | ++_position;
161 | }
162 | }
163 | }
164 |
165 | private void Need(int need) {
166 | while (_position + need >= _data.Length) {
167 | Byte[] newData = new Byte[_data.Length * 2];
168 | _data.CopyTo(newData, 0);
169 |
170 | _data = newData;
171 | }
172 | }
173 |
174 | public virtual long SetData(int len, byte[] data) {
175 | SetUInt((uint)len);
176 | Array.Copy(data, 0, _data, _position, len);
177 |
178 | Advance((uint)len);
179 | return 0;
180 | }
181 |
182 | public virtual long SetData(byte[] toadd) {
183 | return SetData(toadd.Length, toadd);
184 | }
185 |
186 | #endregion
187 |
188 | // Add the standard procedure you requested was called reply header
189 | public virtual void Advance(uint length) {
190 | uint words = (length + 3) / 4;
191 | uint delta = 4 * words;
192 | _position += (int)delta;
193 | }
194 |
195 | public virtual void Reset() {
196 | _position = 0;
197 | }
198 |
199 | }
200 | }
--------------------------------------------------------------------------------
/Application/Udp/UdpHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Globalization;
4 | using System.Net;
5 | using System.Text;
6 | using System.Threading;
7 |
8 | namespace Snarf.Udp {
9 |
10 | public enum UdpReceiverState {
11 | Stopped,
12 | Stopping,
13 | Starting,
14 | Started
15 | }
16 |
17 | public class UdpPacketReceivedEventArgs : EventArgs {
18 |
19 | public UdpPacketReceivedEventArgs(UdpPacket packet, IPEndPoint receivedFrom) {
20 | Packet = packet;
21 | ReceivedFrom = receivedFrom;
22 | }
23 |
24 | public UdpPacket Packet { get; private set; }
25 | public IPEndPoint ReceivedFrom { get; private set; }
26 | }
27 |
28 | public class UdpHandler : IDisposable {
29 |
30 | public event EventHandler PacketReceived = null;
31 |
32 | private Thread _thread = null;
33 | private bool _disposed = false;
34 | protected UdpListener _listener = null;
35 | private long _runState = (long)UdpReceiverState.Stopped;
36 | protected Guid _uniqueId = Guid.Empty;
37 |
38 | public UdpHandler() { }
39 |
40 | public UdpHandler(int port) {
41 |
42 | _uniqueId = Guid.NewGuid();
43 |
44 | _listener = new UdpListener(port, false);
45 | _listener.PacketReceived += OnPacketReceived;
46 | }
47 |
48 | ~UdpHandler() {
49 | this.Dispose(false);
50 | }
51 |
52 | public int Port { get { return _listener.Port; } }
53 |
54 | public virtual void Start() {
55 | if (this._thread == null || this._thread.ThreadState == ThreadState.Stopped) {
56 | this._thread = new Thread(new ThreadStart(this.ThreadStart));
57 | this._thread.Name = String.Format(CultureInfo.InvariantCulture, "UdpHandler:{0}", _uniqueId);
58 | }
59 | else if (this._thread.ThreadState == ThreadState.Running) {
60 | //throw new ThreadStateException("The request handling process is already running.");
61 | return; // allow
62 | }
63 |
64 | if (this._thread.ThreadState != ThreadState.Unstarted) {
65 | throw new ThreadStateException("The request handling process was not properly initialized so it could not be started.");
66 | }
67 | this._thread.Start();
68 |
69 | long waitTime = DateTime.Now.Ticks + TimeSpan.TicksPerSecond * 10;
70 | while (_runState != (long)UdpReceiverState.Started) {
71 | Thread.Sleep(100);
72 | if (DateTime.Now.Ticks > waitTime) {
73 | throw new TimeoutException("Unable to start the request handling process.");
74 | }
75 | }
76 | }
77 |
78 | public virtual void Stop() {
79 | Interlocked.Exchange(ref this._runState, (long)UdpReceiverState.Stopping);
80 | if (_runState == (long)UdpReceiverState.Starting) {
81 | this._listener.Stop();
82 | }
83 | long waitTime = DateTime.Now.Ticks + TimeSpan.TicksPerSecond * 10;
84 | while (_runState != (long)UdpReceiverState.Stopped) {
85 | Thread.Sleep(100);
86 | if (DateTime.Now.Ticks > waitTime) {
87 | throw new TimeoutException("Unable to stop the web server process.");
88 | }
89 | }
90 |
91 | this._thread = null;
92 | }
93 |
94 | private void ThreadStart() {
95 | Interlocked.Exchange(ref this._runState, (long)UdpReceiverState.Starting);
96 | try {
97 | if (_runState != (long)UdpReceiverState.Started) {
98 | this._listener.Start();
99 | Interlocked.Exchange(ref this._runState, (long)UdpReceiverState.Started);
100 | }
101 |
102 | try {
103 | while (_runState == (long)UdpReceiverState.Started) {
104 | //NfsListenerContext context = this._listener.GetContext();
105 | //this.OnPacketReceived(context);
106 | }
107 | }
108 | catch (Exception) {
109 | // This will occur when the listener gets shut down.
110 | // Just swallow it and move on.
111 | }
112 | }
113 | finally {
114 | Interlocked.Exchange(ref this._runState, (long)UdpReceiverState.Stopped);
115 | }
116 | }
117 |
118 | protected virtual void OnPacketReceived(byte[] bytes, IPEndPoint receivedFrom) {
119 | var datagram = new DatagramPacket(bytes, bytes.Length, receivedFrom);
120 | var packet = new UdpPacket(datagram);
121 | var e = new UdpPacketReceivedEventArgs(packet, receivedFrom);
122 | RaisePacketReceived(e);
123 | }
124 |
125 | protected void RaisePacketReceived(UdpPacketReceivedEventArgs e) {
126 | try {
127 | if (this.PacketReceived != null) {
128 | this.PacketReceived.BeginInvoke(this, e, null, null);
129 | }
130 | }
131 | catch {
132 | // Swallow the exception and/or log it, but you probably don't want to exit
133 | // just because an incoming request handler failed.
134 | }
135 | }
136 |
137 | public void Send(UdpPacket packet, IPEndPoint dest) {
138 | //Console.WriteLine("Sending Data: length: " + packet.Length + " -> " + dest.ToString());
139 |
140 | _listener.Client.Send(packet.Data, packet.Length, dest);
141 | }
142 |
143 | #region . IDisposable .
144 |
145 | public virtual void Dispose() {
146 | this.Dispose(true);
147 | GC.SuppressFinalize(this);
148 | }
149 |
150 | private void Dispose(bool disposing) {
151 | if (this._disposed) {
152 | return;
153 | }
154 | if (disposing) {
155 | if (_runState != (long)UdpReceiverState.Stopped) {
156 | this.Stop();
157 | }
158 | if (this._thread != null) {
159 | this._thread.Abort();
160 | this._thread = null;
161 | }
162 | }
163 | this._disposed = true;
164 | }
165 |
166 | #endregion
167 | }
168 |
169 | }
--------------------------------------------------------------------------------
/Application/Nfs/PortmapHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | using Snarf.Udp;
9 |
10 | namespace Snarf.Nfs {
11 |
12 | public class PortmapHandler : BaseHandler {
13 |
14 | public const int PORTMAP_PORT = 111;
15 | public const int PORTMAP_VERSION = 2;
16 | public const int PORTMAP_PROGRAMID = 100000;
17 |
18 | public const int PORTMAP_TRUE = 1;
19 | public const int PORTMAP_FALSE = 0;
20 |
21 | public enum PortmapProcedure : int {
22 | NULL = 0,
23 | SET = 1,
24 | UNSET = 2,
25 | GETPORT = 3,
26 | DUMP = 4,
27 | CALLIT = 5
28 | }
29 |
30 | public enum PortmapMessage : int {
31 | SUCCESS = 0,
32 | PROG_UNAVAIL = 1,
33 | PROG_MISMATCH = 2,
34 | PROC_UNAVAIL = 3,
35 | GARBAGE_ARGS = 4
36 | }
37 |
38 | public PortmapHandler() : base(PORTMAP_PORT, PORTMAP_PROGRAMID) {
39 |
40 | }
41 |
42 | protected override void Process(NfsPacket packet, IPEndPoint receivedFrom) {
43 | //Console.WriteLine("PortmapHandler.Process : recievedFrom: " + receivedFrom.ToString());
44 | //Console.WriteLine("PortmapHandler.Process: Procedure -> " + packet.ProcedureID + ":" + ((PortmapProcedure)packet.ProcedureID).ToString());
45 |
46 | switch (packet.ProcedureID) {
47 | case (int)PortmapProcedure.NULL:
48 | Null(packet, receivedFrom);
49 | break;
50 | case (int)PortmapProcedure.GETPORT:
51 | GetPort(packet, receivedFrom);
52 | break;
53 | case (int)PortmapProcedure.SET:
54 | break;
55 | case (int)PortmapProcedure.UNSET:
56 | break;
57 | case (int)PortmapProcedure.DUMP:
58 | break;
59 | case (int)PortmapProcedure.CALLIT:
60 | break;
61 | default:
62 | break;
63 | }
64 | }
65 |
66 | private void Null(NfsPacket sourcePacket, IPEndPoint receivedFrom) {
67 | // Put together an XDR reply packet
68 | NfsPacket packet = new NfsPacket(128);
69 |
70 | packet.SetUInt(sourcePacket.XID);
71 | packet.SetUInt((uint)RpcSignalType.Reply);
72 | packet.SetUInt((uint)RpcMessageResult.Accepted);
73 |
74 | // Put on a NULL authentication
75 | packet.AddNullAuthentication();
76 |
77 | packet.SetUInt((uint)RpcProcedure.Success);
78 |
79 | Send(packet, receivedFrom);
80 | }
81 |
82 | private void GetPort(NfsPacket sourcePacket, IPEndPoint receivedFrom) {
83 |
84 | // skip past the authentication records
85 | sourcePacket.ReadAuthentication();
86 | sourcePacket.ReadAuthentication();
87 |
88 | // Collect the arguments to the procedure
89 | uint programId = sourcePacket.GetUInt();
90 | uint version = sourcePacket.GetUInt();
91 | uint protocol = sourcePacket.GetUInt();
92 |
93 | // Put together an XDR reply packet
94 | NfsPacket packet = new NfsPacket(128);
95 |
96 | packet.SetUInt(sourcePacket.XID);
97 | packet.SetUInt((uint)RpcSignalType.Reply);
98 | packet.SetUInt((uint)RpcMessageResult.Accepted);
99 |
100 | packet.AddNullAuthentication();
101 |
102 | if (!NfsHandlerManager.IsProgramRegistered((int)programId)) {
103 | packet.SetUInt((uint)RpcProcedure.ProgramUnavailable);
104 | }
105 | else {
106 | // TODO: add version checking. we're only doing v2 right now.
107 | // version mismatch gets the ProgMismatch value.
108 | // result.AddLong(RPCConsts.RPCProgMismatch);
109 | // result.AddLong(versmin);
110 | // result.AddLong(versmax);
111 | int port = NfsHandlerManager.GetPort((int)programId);
112 |
113 | if (port == 0) {
114 | packet.SetUInt((uint)RpcProcedure.ProgramMismatch);
115 | }
116 | else {
117 | packet.SetUInt((uint)RpcProcedure.Success);
118 | packet.SetUInt((uint)port);
119 | }
120 | }
121 |
122 | Send(packet, receivedFrom);
123 | }
124 |
125 | private void Set(NfsPacket sourcePacket, IPEndPoint receivedFrom) {
126 | // skip past the authentication records
127 | sourcePacket.ReadAuthentication();
128 | sourcePacket.ReadAuthentication();
129 |
130 | // Collect the arguments to the procedure
131 | uint programId = sourcePacket.GetUInt();
132 | uint version = sourcePacket.GetUInt();
133 | uint protocol = sourcePacket.GetUInt();
134 | uint port = sourcePacket.GetUInt();
135 |
136 | NfsPacket packet = new NfsPacket(128);
137 |
138 | packet.AddReplyHeader(sourcePacket.XID);
139 | packet.SetUInt(PORTMAP_TRUE);
140 |
141 | // portmapMapping toadd = new portmapMapping(prog, vers, prot);
142 | // toadd.SetPort(port);
143 |
144 | // XDRPacket result = new XDRPacket(128);
145 | // result.AddReplyHeader(xid);
146 |
147 | // // look for the chain of versions for this program
148 | // long? pl = new long?(prog);
149 | // portmapMapping chain = (portmapMapping)mappings[pl];
150 | // if (chain == null) {
151 | // mappings.Add(pl, toadd);
152 | // result.AddLong(Portmap.PM_TRUE);
153 | // }
154 | // else {
155 | // // See if this version is already registered in the chain
156 | // while (chain != null) {
157 | // if (chain.Version() == vers && chain.Protocol() == prot) {
158 | // result.AddLong(Portmap.PM_FALSE);
159 | // break;
160 | // }
161 | // else if (chain.Next() == null) {
162 | // chain.SetNext(toadd);
163 | // result.AddLong(Portmap.PM_TRUE);
164 | // break;
165 | // }
166 | // chain = chain.Next();
167 | // }
168 | // }
169 |
170 | Send(packet, receivedFrom);
171 | }
172 |
173 | }
174 | }
--------------------------------------------------------------------------------
/Application/Snarf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {A74404F2-5664-4C75-BB06-0D1BB0292B60}
8 | Exe
9 | Properties
10 | Snarf
11 | Snarf
12 | v4.5
13 | 512
14 | false
15 | publish\
16 | true
17 | Disk
18 | false
19 | Foreground
20 | 7
21 | Days
22 | false
23 | false
24 | true
25 | 0
26 | 1.0.0.%2a
27 | false
28 | true
29 |
30 |
31 | x86
32 | true
33 | full
34 | false
35 | bin\Debug\
36 | DEBUG;TRACE
37 | prompt
38 | 4
39 |
40 |
41 | AnyCPU
42 | pdbonly
43 | true
44 | bin\Release\
45 | TRACE
46 | prompt
47 | 4
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | Code
67 |
68 |
69 |
70 |
71 |
72 | Code
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | False
98 | Microsoft .NET Framework 4.5 %28x86 and x64%29
99 | true
100 |
101 |
102 | False
103 | .NET Framework 3.5 SP1 Client Profile
104 | false
105 |
106 |
107 | False
108 | .NET Framework 3.5 SP1
109 | false
110 |
111 |
112 |
113 |
114 | {f7f1f64d-f6cd-42a9-b167-546e4ea31463}
115 | Shellscape.Common
116 |
117 |
118 |
119 |
126 |
--------------------------------------------------------------------------------
/Application/Nfs/FileSystem/NfsFileAttributes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Security.Permissions;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Snarf.Nfs.FileSystem {
10 |
11 | // The file attributes that NFS needs.
12 | //
13 | // From:
14 | // Sun Microsystems, Inc. [Page 15]
15 | // RFC 1094 NFS: Network File System March 1989
16 | //
17 | public class NfsFileAttributes {
18 |
19 | private FileType type;
20 | private FilePermissions mode;
21 |
22 | private uint nlink;
23 | private uint uid;
24 | private uint gid;
25 | private uint size;
26 | private uint blocksize;
27 | private uint rdev;
28 | private uint blocks;
29 | private uint fsid;
30 | private uint fileid;
31 |
32 | private NfsTime lastAccessed;
33 | private NfsTime lastModified;
34 | private NfsTime lastChanged;
35 |
36 | [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
37 | public static extern bool GetFileInformationByHandle(IntPtr hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);
38 |
39 | [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
40 | public struct FILETIME {
41 | public uint DateTimeLow;
42 | public uint DateTimeHigh;
43 | }
44 |
45 | public struct BY_HANDLE_FILE_INFORMATION {
46 | public uint FileAttributes;
47 | public FILETIME CreationTime;
48 | public FILETIME LastAccessTime;
49 | public FILETIME LastWriteTime;
50 | public uint VolumeSerialNumber;
51 | public uint FileSizeHigh;
52 | public uint FileSizeLow;
53 | public uint NumberOfLinks;
54 | public uint FileIndexHigh;
55 | public uint FileIndexLow;
56 | }
57 |
58 | public NfsFileAttributes() { }
59 |
60 | public NfsFileAttributes(String path) {
61 | Load(path);
62 | }
63 |
64 | public bool Read(NfsPacket packet) {
65 | type = (FileType)packet.GetUInt();
66 | mode = (FilePermissions)packet.GetUInt();
67 | nlink = packet.GetUInt();
68 | uid = packet.GetUInt();
69 | gid = packet.GetUInt();
70 | size = packet.GetUInt();
71 | blocksize = packet.GetUInt();
72 | rdev = packet.GetUInt();
73 | blocks = packet.GetUInt();
74 | fsid = packet.GetUInt();
75 | fileid = packet.GetUInt();
76 |
77 | if (!lastAccessed.Read(packet)) {
78 | return false;
79 | }
80 | if (!lastModified.Read(packet)) {
81 | return false;
82 | }
83 | if (!lastChanged.Read(packet)) {
84 | return false;
85 | }
86 |
87 | return true;
88 | }
89 |
90 | public bool Emit(ref NfsPacket packet) {
91 | packet.SetUInt((uint)type);
92 | packet.SetUInt((uint)mode);
93 | packet.SetUInt(nlink);
94 | packet.SetUInt(uid);
95 | packet.SetUInt(gid);
96 | packet.SetUInt(size);
97 | packet.SetUInt(blocksize);
98 | packet.SetUInt(rdev);
99 | packet.SetUInt(blocks);
100 | packet.SetUInt(fsid);
101 | packet.SetUInt(fileid);
102 |
103 | if (!lastAccessed.Emit(ref packet)) {
104 | return false;
105 | }
106 | if (!lastModified.Emit(ref packet)) {
107 | return false;
108 | }
109 | if (!lastChanged.Emit(ref packet)) {
110 | return false;
111 | }
112 |
113 | return true;
114 | }
115 |
116 | public uint Load(String path) {
117 |
118 | if (!File.Exists(path) && !Directory.Exists(path)) {
119 | throw new FileNotFoundException();
120 | }
121 |
122 | mode = 0;
123 |
124 | FileAttributes fileAttributes = File.GetAttributes(path);
125 | Boolean isDirectory = fileAttributes.Is(FileAttributes.Directory);
126 | Boolean canRead = NfsFileAttributes.CanRead(path);
127 | Boolean canWrite = NfsFileAttributes.CanWrite(path);
128 |
129 | if (!isDirectory) {
130 | type = FileType.NFREG;
131 | mode = FilePermissions.UPFILE;
132 | }
133 | else if (isDirectory) {
134 | type = FileType.NFDIR;
135 | mode = FilePermissions.UPDIR;
136 | }
137 | else {
138 | Console.Error.WriteLine("NfsFileAttributes.Load: " + path + " has unknown type");
139 | type = FileType.NFNON;
140 | mode = 0; // don't know what kind of file system object this is
141 | }
142 |
143 | //if (!isDirectory) {
144 | // using (var fs = new FileStream(path, FileMode.Open)) {
145 | // canRead = fs.CanRead;
146 | // canWrite = fs.CanWrite;
147 | // }
148 | //}
149 | //else {
150 | // canRead = true;
151 | // canWrite = !fileAttributes.Is(FileAttributes.ReadOnly);
152 | //}
153 |
154 | if (canRead) {
155 | mode |= FilePermissions.UP_OREAD | FilePermissions.UP_GREAD | FilePermissions.UP_WREAD;
156 | mode |= FilePermissions.UP_OEXEC | FilePermissions.UP_GEXEC | FilePermissions.UP_WEXEC;
157 | }
158 | if (canWrite) {
159 | mode |= FilePermissions.UP_OWRITE | FilePermissions.UP_GWRITE | FilePermissions.UP_WWRITE;
160 | }
161 |
162 | // from now on assume either file or directory
163 | if (!isDirectory) {
164 | nlink = 1;
165 | }
166 | else { // directories always have 2 links
167 | nlink = 2;
168 | }
169 |
170 | FileInfo file = new FileInfo(path);
171 |
172 | uid = 0;
173 | gid = 0;
174 | size = isDirectory ? 512 : (uint)(new FileInfo(path).Length);
175 | blocksize = 512; // XXX common value, how do I get this in java?
176 | rdev = 0;
177 | blocks = (size + blocksize - 1) / blocksize;
178 | fsid = isDirectory ? 0 : GetFileSystemId(file);
179 | fileid = (uint)HandleManager.Current.GetHandle(path);
180 |
181 | lastAccessed = new NfsTime(file.LastAccessTime);
182 | lastChanged = new NfsTime(file.LastWriteTime);
183 | lastModified = new NfsTime(file.LastWriteTime);
184 |
185 | return (uint)NfsReply.OK;
186 | }
187 |
188 | public uint GetFileSystemId(FileInfo file) {
189 | BY_HANDLE_FILE_INFORMATION objectFileInfo = new BY_HANDLE_FILE_INFORMATION();
190 |
191 | try {
192 | using (FileStream fs = file.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
193 | GetFileInformationByHandle(fs.SafeFileHandle.DangerousGetHandle(), out objectFileInfo);
194 | }
195 | }
196 | catch (Exception) {
197 | return 0;
198 | }
199 |
200 | uint fileIndex = (objectFileInfo.FileIndexHigh << 32) + objectFileInfo.FileIndexLow;
201 |
202 | return fileIndex;
203 | }
204 |
205 | public static bool IsDirectory(string path) {
206 | FileAttributes fileAttributes = File.GetAttributes(path);
207 | return fileAttributes.Is(FileAttributes.Directory);
208 | }
209 |
210 | private static Boolean Can(String path, FileIOPermissionAccess value) {
211 | FileIOPermission fp = new FileIOPermission(value, path);
212 |
213 | try {
214 | fp.Demand();
215 | }
216 | catch (System.Security.SecurityException) {
217 | return false;
218 | }
219 |
220 | return true;
221 | }
222 |
223 | public static Boolean CanRead(String path) {
224 | return Can(path, FileIOPermissionAccess.Read);
225 | }
226 |
227 | public static Boolean CanWrite(String path) {
228 | return Can(path, FileIOPermissionAccess.Write);
229 | }
230 |
231 | }
232 |
233 | }
234 |
--------------------------------------------------------------------------------
/Application/Udp/UdpListener.cs:
--------------------------------------------------------------------------------
1 | // resused from http://growl-for-windows.googlecode.com/svn-history/r125/trunk/Growl/Growl.UDPLegacy/UdpListener.cs
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Net.NetworkInformation;
7 | using System.Net.Sockets;
8 | using System.Text;
9 |
10 | namespace Snarf.Udp {
11 |
12 | ///
13 | /// Simple class to represent state when used with a UdpListener
14 | ///
15 | public class UdpState {
16 | public UdpClient Udp;
17 | public IPEndPoint Endpoint;
18 | public AsyncCallback Callback;
19 | }
20 |
21 | ///
22 | /// A basic listener that listens for incoming UDP messages on the specified port
23 | /// and passes the event on to application code whenever a message is received.
24 | ///
25 | public class UdpListener : IDisposable {
26 |
27 | private static object syncLock = new object();
28 | private static Dictionary masks;
29 |
30 | private Boolean _started = false;
31 |
32 | ///
33 | /// The port to listen for messages on
34 | ///
35 | protected int port;
36 | ///
37 | /// Indicates if messages from remote machines should be allowed or not
38 | ///
39 | protected bool localMessagesOnly = true;
40 | ///
41 | /// The underlying
42 | ///
43 | protected UdpClient udp;
44 | ///
45 | /// Event handlder for the event
46 | ///
47 | /// The raw packet data
48 | /// The host that sent the message
49 | /// Indicates if the request came from the local machine
50 | /// Indicates if the request came from the LAN
51 | public delegate void PacketHandler(byte[] bytes, IPEndPoint receivedFrom);
52 | ///
53 | /// Fires when a message is received
54 | ///
55 | public event PacketHandler PacketReceived;
56 |
57 | ///
58 | /// Creates a new
59 | ///
60 | /// The port to listen for messages on
61 | /// true to only listen for messages from the local machine;false to listen for messages from any source
62 | public UdpListener(int port, bool localMessagesOnly) {
63 | this.port = port;
64 | this.localMessagesOnly = localMessagesOnly;
65 | }
66 |
67 | public int Port { get { return port; } }
68 |
69 | public UdpClient Client { get { return udp; } }
70 |
71 | public void Start() {
72 | Start(null);
73 | }
74 |
75 | ///
76 | /// Starts listening for messages on the specified port
77 | ///
78 | public void Start(AsyncCallback callback) {
79 |
80 | if (_started) {
81 | return;
82 | }
83 |
84 | _started = true;
85 |
86 | IPAddress address = (this.localMessagesOnly ? IPAddress.Loopback : IPAddress.Any);
87 | IPEndPoint endpoint = new IPEndPoint(address, this.port);
88 | this.udp = new UdpClient(endpoint);
89 | this.port = ((IPEndPoint)udp.Client.LocalEndPoint).Port; // if 0 is passed, the system will assign a port.
90 |
91 | if (callback == null) {
92 | callback = new AsyncCallback(this.ProcessPacket);
93 | }
94 |
95 | UdpState state = new UdpState();
96 | state.Udp = udp;
97 | state.Endpoint = endpoint;
98 | state.Callback = callback;
99 |
100 | udp.BeginReceive(callback, state);
101 | }
102 |
103 | ///
104 | /// Stops listening for messages and frees the port
105 | ///
106 | public void Stop() {
107 | if (!_started) {
108 | return;
109 | }
110 |
111 | _started = false;
112 |
113 | try {
114 | this.udp.Close();
115 | this.udp = null;
116 | }
117 | finally {
118 | }
119 | }
120 |
121 | ///
122 | /// When a message is received by the listener, the raw data is read from the packet
123 | /// and the event is fired.
124 | ///
125 | ///
126 | private void ProcessPacket(IAsyncResult ar) {
127 | try {
128 | UdpClient udp = (UdpClient)((UdpState)(ar.AsyncState)).Udp;
129 | IPEndPoint endpoint = (IPEndPoint)((UdpState)(ar.AsyncState)).Endpoint;
130 | AsyncCallback callback = (AsyncCallback)((UdpState)(ar.AsyncState)).Callback;
131 |
132 | byte[] bytes = udp.EndReceive(ar, ref endpoint);
133 |
134 | IPAddress localAddress = IPAddress.Loopback;
135 | IPEndPoint localEndpoint = (IPEndPoint)udp.Client.LocalEndPoint;
136 | if (localEndpoint != null) localAddress = localEndpoint.Address;
137 |
138 | //bool isLocal = IPAddress.IsLoopback(endpoint.Address);
139 | //bool isLAN = IsInSameSubnet(localAddress, endpoint.Address);
140 | //string receivedFrom = endpoint.ToString();
141 |
142 | // start listening again
143 | udp.BeginReceive(callback, ar.AsyncState);
144 |
145 | // bubble up the event
146 | if (this.PacketReceived != null) this.PacketReceived(bytes, endpoint);
147 | }
148 | catch (Exception e) {
149 | // swallow any exceptions (this handles the case when Growl is stopped while still listening for network notifications)
150 | }
151 | }
152 |
153 | public static bool IsInSameSubnet(IPAddress localAddress, IPAddress otherAddress) {
154 | try {
155 | // handle loopback addresses and IPv6 local addresses
156 | if (IPAddress.IsLoopback(otherAddress)
157 | || otherAddress.IsIPv6LinkLocal
158 | || otherAddress.IsIPv6SiteLocal)
159 | return true;
160 |
161 | IPAddress subnetMask = GetLocalSubnetMask(localAddress);
162 | IPAddress network1 = GetNetworkAddress(localAddress, subnetMask);
163 | IPAddress network2 = GetNetworkAddress(otherAddress, subnetMask);
164 | return network1.Equals(network2);
165 | }
166 | catch {
167 | Console.WriteLine(String.Format("Could not determine subnet. Local address: {0} - Remote Address: {1}", localAddress, otherAddress));
168 | }
169 | return false;
170 | }
171 |
172 | public static IPAddress GetLocalSubnetMask(IPAddress ipaddress) {
173 | lock (syncLock) {
174 | if (masks == null) {
175 | masks = new Dictionary();
176 |
177 | NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
178 | foreach (NetworkInterface ni in interfaces) {
179 | //Console.WriteLine(ni.Description);
180 |
181 | UnicastIPAddressInformationCollection unicastAddresses = ni.GetIPProperties().UnicastAddresses;
182 | foreach (UnicastIPAddressInformation unicastAddress in unicastAddresses) {
183 | IPAddress mask = (unicastAddress.IPv4Mask != null ? unicastAddress.IPv4Mask : IPAddress.None);
184 | masks.Add(unicastAddress.Address, mask);
185 |
186 | //Console.WriteLine("\tIP Address is {0}", unicastAddress.Address);
187 | //Console.WriteLine("\tSubnet Mask is {0}", mask);
188 | }
189 | }
190 | }
191 | }
192 |
193 | if (masks.ContainsKey(ipaddress))
194 | return masks[ipaddress];
195 | else
196 | return IPAddress.None;
197 | }
198 |
199 | public static IPAddress GetNetworkAddress(IPAddress address, IPAddress subnetMask) {
200 | byte[] ipAdressBytes = address.GetAddressBytes();
201 | byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
202 |
203 | if (ipAdressBytes.Length != subnetMaskBytes.Length)
204 | throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
205 |
206 | byte[] broadcastAddress = new byte[ipAdressBytes.Length];
207 | for (int i = 0; i < broadcastAddress.Length; i++) {
208 | broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i]));
209 | }
210 | return new IPAddress(broadcastAddress);
211 | }
212 |
213 | #region IDisposable Members
214 |
215 | public void Dispose() {
216 | this.Dispose(true);
217 | GC.SuppressFinalize(this);
218 | }
219 |
220 | protected void Dispose(bool disposing) {
221 | if (disposing) {
222 | try {
223 | if (this.udp != null) this.udp.Close();
224 | }
225 | catch {
226 | // suppress
227 | }
228 | }
229 | }
230 |
231 | #endregion
232 | }
233 | }
--------------------------------------------------------------------------------
/Application/Nfs/FileSystem/NfsDirectory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | namespace Snarf.Nfs.FileSystem {
7 |
8 | internal class NfsDirectory {
9 |
10 | private FileSystemInfo _fsInfo;
11 |
12 | // keep these between calls so subsequent calls getting the rest of the contents of a directory are fast.
13 | private String _cachedDirectories;
14 | private List _cachedFiles;
15 |
16 | public NfsDirectory(FileSystemInfo fsInfo) {
17 | _fsInfo = fsInfo;
18 | }
19 |
20 | public virtual NfsPacket GetAttr(NfsPacket packet) {
21 | try {
22 | FileHandle f = new FileHandle(packet);
23 | NfsFileAttributes fa = new NfsFileAttributes();
24 |
25 | string file = GetNameFromHandle(f.Handle, packet.XID);
26 |
27 | if (!File.Exists(file) && !Directory.Exists(file)) {
28 | throw new NFSException(packet.XID, (uint)NfsReply.ERR_NOENT);
29 | }
30 |
31 | Console.WriteLine("NfsDirectory.GetAttr: file: " + file);
32 | fa.Load(file);
33 |
34 | NfsPacket reply = new NfsPacket(96);
35 | reply.AddReplyHeader(packet.XID);
36 | reply.SetUInt((uint)NfsReply.OK);
37 |
38 | fa.Emit(ref reply);
39 |
40 | return reply;
41 | }
42 | catch (FileNotFoundException) {
43 | throw new NFSException(packet.XID, (uint)NfsReply.ERR_NOENT);
44 | }
45 | }
46 |
47 | public virtual NfsPacket SetAttr(uint xid, NfsPacket packet) {
48 | try {
49 | FileHandle f = new FileHandle(packet);
50 | String fileName = GetNameFromHandle(f.Handle, xid);
51 |
52 | // the attributes
53 | int mode = (int)packet.GetUInt();
54 | int uid = (int)packet.GetUInt();
55 | int gid = (int)packet.GetUInt();
56 | int size = (int)packet.GetUInt();
57 | NfsTime atime = new NfsTime(packet);
58 | NfsTime mtime = new NfsTime(packet);
59 |
60 | // the only attribute that can be set is the size can be set to 0 to truncate the file
61 | if (size == 0) {
62 | // truncate by deleting and recreating the file
63 | using (var fs = new FileStream(fileName, FileMode.Truncate, FileAccess.ReadWrite)) { }
64 | }
65 |
66 | NfsPacket reply = new NfsPacket(128);
67 | reply.AddReplyHeader(xid);
68 | reply.SetUInt((uint)NfsReply.OK);
69 |
70 | NfsFileAttributes fa = new NfsFileAttributes();
71 | fa.Load(fileName);
72 | fa.Emit(ref reply);
73 |
74 | return reply;
75 | }
76 | catch (FileNotFoundException) {
77 | throw new NFSException(xid, (uint)NfsReply.ERR_NOENT);
78 | }
79 | catch (IOException) {
80 | throw new NFSException(xid, (uint)NfsReply.ERR_PERM);
81 | }
82 | }
83 |
84 | public virtual NfsPacket Lookup(NfsPacket packet) {
85 | try {
86 | FileHandle dir = new FileHandle(packet);
87 | String entry = packet.GetString();
88 | String dirName = GetNameFromHandle(dir.Handle, packet.XID);
89 | String fileName = Path.Combine(dirName, entry);
90 |
91 | Console.WriteLine("Lookup -> " + entry);
92 |
93 | if (!File.Exists(fileName) && !Directory.Exists(fileName)) {
94 | throw new NFSException(packet.XID, (uint)NfsReply.ERR_NOENT);
95 | }
96 |
97 | NfsFileAttributes attributes = new NfsFileAttributes();
98 | attributes.Load(fileName);
99 |
100 | // make a FileHandle for this new path
101 | uint handleId = HandleManager.Current.GetHandle(fileName);
102 |
103 | FileHandle handle = new FileHandle();
104 | handle.Set(dir.Root, handleId, dir.ReadOnly);
105 |
106 | // make the reply
107 | NfsPacket reply = new NfsPacket(128);
108 | reply.AddReplyHeader(packet.XID);
109 | reply.SetUInt((uint)NfsReply.OK);
110 |
111 | handle.Emit(ref reply);
112 | attributes.Emit(ref reply);
113 |
114 | return reply;
115 |
116 | }
117 | catch (FileNotFoundException) {
118 | throw new NFSException(packet.XID, (uint)NfsReply.ERR_NOENT);
119 | }
120 | }
121 |
122 | public virtual NfsPacket ReadDirectory(NfsPacket packet) {
123 |
124 | FileHandle fh = new FileHandle(packet);
125 | uint cookie = packet.GetUInt();
126 | uint count = packet.GetUInt();
127 | uint xId = packet.XID;
128 |
129 | // if this is a new call to readdir (cookie=0) or it is a new directory to read, replace the cache.
130 | string dirName = GetNameFromHandle(fh.Handle, xId);
131 |
132 | //Console.Write("Reading dir " + dirName + " cookie=" + cookie + " count=" + count + "\n");
133 |
134 | if (cookie == 0 || (dirName.Equals(_cachedDirectories) == false)) {
135 |
136 | if (!Directory.Exists(dirName)) {
137 | throw new NFSException(xId, (uint)NfsReply.ERR_NOENT);
138 | }
139 |
140 | List dirFiles = Directory.GetFiles(dirName).Select(f => new FileInfo(f).Name).ToList();
141 | dirFiles.AddRange(Directory.GetDirectories(dirName).Select(d => new DirectoryInfo(d).Name));
142 |
143 | if (dirFiles == null) {
144 | throw new NFSException(xId, (uint)NfsReply.ERR_NOENT);
145 | }
146 |
147 | //Console.WriteLine("dir has " + dirFiles.Count + " entries");
148 |
149 | if (dirFiles.Count <= 0) {
150 | throw new NFSException(xId, (uint)NfsReply.ERR_NOENT);
151 | }
152 |
153 | dirFiles.BubbleSort();
154 | //dirFiles.Insert(0, "..");
155 | //dirFiles.Insert(0, ".");
156 |
157 | _cachedFiles = dirFiles;
158 | _cachedDirectories = dirName;
159 | }
160 |
161 | // prepare the reply packet.
162 | NfsPacket reply = new NfsPacket((int)count);
163 | reply.AddReplyHeader(xId);
164 | reply.SetUInt((uint)NfsReply.OK);
165 |
166 | // Add files to the list until there are no more files or all of the count bytes have been used.
167 |
168 | int current = reply.Length;
169 | bool more = false; // are there more files to get
170 |
171 | // if there are any files to add
172 | if (_cachedFiles != null && _cachedFiles.Count > 0) {
173 | for (int i = (int)cookie; i < _cachedFiles.Count; i++) {
174 | // see if there is enough room for another file - 3 longs of id,
175 | // the name (rounded up to 4 bytes) and a trailing long
176 | // indicating whether there are more files to get
177 | int needed = 3 * 4 + (_cachedFiles[i].Length + 3) + 8;
178 | if (needed + current >= count) {
179 | more = true;
180 | break;
181 | }
182 | // get the handle for this file
183 | string fileName = Path.Combine(_cachedDirectories, _cachedFiles[i]);
184 | uint handle = HandleManager.Current.GetHandle(fileName);
185 |
186 | Console.WriteLine("Read handle for: " + fileName + " -> " + handle);
187 |
188 | // add an entry to the packet for this file
189 | reply.SetUInt(NfsHandler.NFS_TRUE);
190 | reply.SetUInt(handle);
191 | reply.Set(_cachedFiles[i]);
192 | reply.SetUInt((uint)i + 1); // this is the cookie
193 |
194 | current = reply.Length;
195 | }
196 | }
197 | reply.SetUInt(NfsHandler.NFS_FALSE); // no more entries in this packet
198 |
199 | // tell the client if this packet has returned the last of the files
200 | if (more) {
201 | reply.SetUInt(NfsHandler.NFS_FALSE);
202 | }
203 | else {
204 | reply.SetUInt(NfsHandler.NFS_TRUE);
205 | }
206 |
207 | return reply;
208 | }
209 |
210 | public virtual NfsPacket Create(uint xid, NfsPacket packet) {
211 | try {
212 | FileHandle dirFH = new FileHandle(packet);
213 | string entry = packet.GetString();
214 | string dirName = GetNameFromHandle(dirFH.Handle, xid);
215 | string path = Path.Combine(dirName, entry);
216 |
217 | // make the file
218 |
219 | if (File.Exists(path)) {
220 | throw new NFSException(xid, (uint)NfsReply.ERR_EXIST);
221 | }
222 |
223 | using (var file = File.Create(path)) { }
224 |
225 | // make a new handle for this file
226 | FileHandle fh = new FileHandle();
227 | long handle = HandleManager.Current.GetHandle(path);
228 | fh.Set(dirFH.Root, (uint)handle, dirFH.ReadOnly);
229 |
230 | // get the attributes of this new file
231 | NfsFileAttributes fa = new NfsFileAttributes();
232 | fa.Load(path);
233 |
234 | // create the reply packet
235 | NfsPacket reply = new NfsPacket(128);
236 | reply.AddReplyHeader(xid);
237 | reply.SetUInt((uint)NfsReply.OK);
238 | fh.Emit(ref reply);
239 | fa.Emit(ref reply);
240 | return reply;
241 |
242 | }
243 | catch (FileNotFoundException) {
244 | throw new NFSException(xid, (uint)NfsReply.ERR_IO);
245 | }
246 | catch (IOException) {
247 | throw new NFSException(xid, (uint)NfsReply.ERR_IO);
248 | }
249 | catch (System.Security.SecurityException) {
250 | throw new NFSException(xid, (uint)NfsReply.ERR_PERM);
251 | }
252 | }
253 |
254 | public virtual NfsPacket Remove(uint xid, NfsPacket packet) {
255 | FileHandle fileHandle = new FileHandle(packet);
256 | string entry = packet.GetString();
257 |
258 | // open and delete the file
259 | string dirName = GetNameFromHandle(fileHandle.Handle, xid);
260 | var fd = new FileInfo(Path.Combine(dirName, entry));
261 | if (fd.Exists == false) {
262 | throw new NFSException(xid, (uint)NfsReply.ERR_NOENT);
263 | }
264 | try {
265 | fd.Delete();
266 | }
267 | catch (Exception) {
268 | throw new NFSException(xid, (uint)NfsReply.ERR_IO);
269 | }
270 |
271 | // create the reply packet
272 | NfsPacket reply = new NfsPacket(128);
273 | reply.AddReplyHeader(xid);
274 | reply.SetUInt((uint)NfsReply.OK);
275 | return reply;
276 | }
277 |
278 | public virtual NfsPacket Mkdir(uint xid, NfsPacket packet) {
279 | try {
280 | FileHandle fileHandle = new FileHandle(packet);
281 | string entry = packet.GetString();
282 |
283 | string dirName = GetNameFromHandle(fileHandle.Handle, xid);
284 | string newdir = Path.Combine(dirName, entry);
285 |
286 | var dir = new DirectoryInfo(newdir);
287 |
288 | if (dir.Exists) {
289 | throw new NFSException(xid, (uint)NfsReply.ERR_EXIST);
290 | }
291 |
292 | dir.Create();
293 |
294 | // make a FileHandle for this directory
295 | long handle = HandleManager.Current.GetHandle(newdir);
296 | FileHandle newFH = new FileHandle();
297 | newFH.Set(fileHandle.Root, (uint)handle, fileHandle.ReadOnly);
298 |
299 | // get the attributes
300 | NfsFileAttributes fa = new NfsFileAttributes();
301 | fa.Load(newdir);
302 |
303 | NfsPacket reply = new NfsPacket(128);
304 | reply.AddReplyHeader(xid);
305 | reply.SetUInt((uint)NfsReply.OK);
306 | newFH.Emit(ref reply);
307 | fa.Emit(ref reply);
308 | return reply;
309 |
310 | }
311 | catch (FileNotFoundException) {
312 | throw new NFSException(xid, (uint)NfsReply.ERR_IO);
313 | }
314 | }
315 |
316 | public virtual NfsPacket Rmdir(uint xid, NfsPacket packet) {
317 | FileHandle fileHandle = new FileHandle(packet);
318 | string name = packet.GetString();
319 |
320 | string dirname = GetNameFromHandle(fileHandle.Handle, xid);
321 | var fd = new FileInfo(Path.Combine(dirname, name));
322 | // do some correctness checking
323 | if (fd.Exists == false) {
324 | throw new NFSException(xid, (uint)NfsReply.ERR_NOENT);
325 | }
326 | if (NfsFileAttributes.IsDirectory(fd.FullName) == false) {
327 | throw new NFSException(xid, (uint)NfsReply.ERR_NOTDIR);
328 | }
329 | // try to remove the directory
330 | try {
331 | fd.Delete();
332 | }
333 | catch (Exception) {
334 | throw new NFSException(xid, (uint)NfsReply.ERR_IO);
335 | }
336 |
337 | NfsPacket reply = new NfsPacket(128);
338 | reply.AddReplyHeader(xid);
339 | reply.SetUInt((uint)NfsReply.OK);
340 | return reply;
341 | }
342 |
343 | public virtual NfsPacket StatFS(NfsPacket packet) {
344 | FileHandle fh = new FileHandle(packet);
345 | // tell the fsinfo the path to get information about
346 | _fsInfo.SetFS(GetNameFromHandle(fh.Handle, packet.XID));
347 |
348 | NfsPacket reply = new NfsPacket(128);
349 | reply.AddReplyHeader(packet.XID);
350 | reply.SetUInt((uint)NfsReply.OK);
351 | reply.SetUInt(_fsInfo.TransferSize);
352 | reply.SetUInt(_fsInfo.BlockSize);
353 | reply.SetUInt(_fsInfo.TotalBlocks);
354 | reply.SetUInt(_fsInfo.FreeBlocks);
355 | reply.SetUInt(_fsInfo.AvailableBlocks);
356 | return reply;
357 | }
358 |
359 | public virtual NfsPacket Rename(uint xid, NfsPacket packet) {
360 | // collect arguments from RPC packet
361 | FileHandle sourceHandle = new FileHandle(packet);
362 | string srcentry = packet.GetString();
363 |
364 | FileHandle destHandle = new FileHandle(packet);
365 | string destentry = packet.GetString();
366 |
367 | // compute the path names specified
368 | String srcdir = GetNameFromHandle(sourceHandle.Handle, xid);
369 | String destdir = GetNameFromHandle(destHandle.Handle, xid);
370 |
371 | FileInfo source = new FileInfo(Path.Combine(srcdir, srcentry));
372 | FileInfo dest = new FileInfo(Path.Combine(destdir, destentry));
373 |
374 | if (source.Exists == false) {
375 | throw new NFSException(xid, (uint)NfsReply.ERR_NOENT);
376 | }
377 |
378 | if (dest.Exists) {
379 | throw new NFSException(xid, (uint)NfsReply.ERR_EXIST);
380 | }
381 |
382 | try {
383 | source.MoveTo(dest.FullName);
384 | }
385 | catch (Exception) {
386 | throw new NFSException(xid, (uint)NfsReply.ERR_IO);
387 | }
388 |
389 | NfsPacket reply = new NfsPacket(128);
390 | reply.AddReplyHeader(xid);
391 | reply.SetUInt((uint)NfsReply.OK);
392 | return reply;
393 | }
394 |
395 | // local procedure to get the associated with a handle, throws an exception if there is a problem.
396 | private string GetNameFromHandle(uint handle, uint xid) {
397 | String result = HandleManager.Current.GetName(handle);
398 | if (result == null) {
399 | throw new NFSException(xid, (int)NfsReply.ERR_STALE);
400 | }
401 | return result;
402 | }
403 | }
404 | }
--------------------------------------------------------------------------------