Toby Chui 1 rok temu
rodzic
commit
975f09ac1c
6 zmienionych plików z 442 dodań i 110 usunięć
  1. 5 1
      go.mod
  2. 27 0
      go.sum
  3. 75 15
      mod/fileservers/servers/nfsserv/nfsserv.go
  4. 104 93
      mod/info/logger/logger.go
  5. 211 0
      mod/storage/billyconv/billyconv.go
  6. 20 1
      network.go

+ 5 - 1
go.mod

@@ -63,13 +63,17 @@ require (
 	github.com/klauspost/compress v1.17.4 // indirect
 	github.com/klauspost/pgzip v1.2.6 // indirect
 	github.com/kr/fs v0.1.0 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/miekg/dns v1.1.57 // indirect
 	github.com/nwaples/rardecode v1.1.3 // indirect
 	github.com/pierrec/lz4/v4 v4.1.19 // indirect
 	github.com/pjbgf/sha1cd v0.3.0 // indirect
 	github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93 // indirect
+	github.com/rs/zerolog v1.32.0 // indirect
 	github.com/sergi/go-diff v1.3.1 // indirect
 	github.com/skeema/knownhosts v1.2.1 // indirect
+	github.com/smallfz/libnfs-go v0.0.5 // indirect
 	github.com/ulikunitz/xz v0.5.11 // indirect
 	github.com/willscott/go-nfs-client v0.0.0-20200605172546-271fa9065b33 // indirect
 	github.com/xanzy/ssh-agent v0.3.3 // indirect
@@ -78,7 +82,7 @@ require (
 	golang.org/x/image v0.15.0 // indirect
 	golang.org/x/mod v0.14.0 // indirect
 	golang.org/x/net v0.23.0 // indirect
-	golang.org/x/sys v0.18.0 // indirect
+	golang.org/x/sys v0.20.0 // indirect
 	golang.org/x/text v0.14.0 // indirect
 	golang.org/x/tools v0.16.1 // indirect
 	google.golang.org/appengine v1.6.8 // indirect

+ 27 - 0
go.sum

@@ -22,6 +22,8 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH
 github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
 github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
 github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
 github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -61,6 +63,7 @@ github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
 github.com/go-ldap/ldap v3.0.3+incompatible h1:HTeSZO8hWMS1Rgb2Ziku6b8a7qRIZZMHjsvuZyatzwk=
 github.com/go-ldap/ldap v3.0.3+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
 github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
@@ -117,6 +120,12 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
 github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
 github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
@@ -148,6 +157,11 @@ github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93/go.mod h1:Nfe4efndBz4
 github.com/robertkrimen/otto v0.3.0 h1:5RI+8860NSxvXywDY9ddF5HcPw0puRsd8EgbXV0oqRE=
 github.com/robertkrimen/otto v0.3.0/go.mod h1:uW9yN1CYflmUQYvAMS0m+ZiNo3dMzRUDQJX0jWbzgxw=
 github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
+github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo=
+github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
+github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
 github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 h1:PT+ElG/UUFMfqy5HrxJxNzj3QBOf7dZwupeVC+mG1Lo=
@@ -156,6 +170,8 @@ github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NF
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
 github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
+github.com/smallfz/libnfs-go v0.0.5 h1:R8+c7qlfeShrXAcZgXQy+r6PCHcipy6B8xi9hRbxxI0=
+github.com/smallfz/libnfs-go v0.0.5/go.mod h1:ShmRLPyTV/ikl0E/C4ythuUwSJmKiVmHB/MIWx8zErg=
 github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
 github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -179,6 +195,7 @@ github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM
 github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
 github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
 github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
+github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 github.com/zema1/go-nfs-client v0.0.0-20200604081958-0cf942f0e0fe/go.mod h1:im3CVJ32XM3+E+2RhY0sa5IVJVQehUrX0oE1wX4xOwU=
 gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40 h1:dizWJqTWjwyD8KGcMOwgrkqu1JIkofYgKkmDeNE7oAs=
@@ -200,6 +217,7 @@ golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+o
 golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
 golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
@@ -210,6 +228,7 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
@@ -221,6 +240,7 @@ golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
 golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
 golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
@@ -234,16 +254,21 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
 golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -264,6 +289,7 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
@@ -271,6 +297,7 @@ golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
 google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=

+ 75 - 15
mod/fileservers/servers/nfsserv/nfsserv.go

@@ -3,34 +3,94 @@ package nfsserv
 import (
 	"fmt"
 	"net"
+	"strconv"
 
-	nfs "github.com/willscott/go-nfs"
+	"github.com/smallfz/libnfs-go/backend"
+	"github.com/smallfz/libnfs-go/memfs"
+	server "github.com/smallfz/libnfs-go/server"
+	"imuslab.com/arozos/mod/fileservers"
+	"imuslab.com/arozos/mod/info/logger"
 	"imuslab.com/arozos/mod/permission"
+	"imuslab.com/arozos/mod/user"
 )
 
 type Option struct {
+	UserManager      *user.UserHandler
 	ListeningPort    int
-	AllowAccessGroup *permission.PermissionGroup
+	AllowAccessGroup []*permission.PermissionGroup
+	Logger           *logger.Logger
 }
 
-type Instance struct {
-	server    *nfs.Server
-	isRunning bool
-	option    *Option
+type Manager struct {
+	server      *server.Server //NFS server
+	tcpListener net.Listener   //Underlaying TCP connection lisener
+	isRunning   bool
+	Option      *Option
 }
 
 // Create a new NFS Server
-func NewNfsServer(option Option) (*Instance, error) {
-	// Check if the listening port is free and not occupied by another application
-	l, err := net.Listen("tcp", fmt.Sprintf(":%d", option.ListeningPort))
-	if err != nil {
-		return nil, err
+func NewNfsServer(option Option) *Manager {
+	if option.Logger == nil {
+		//Create a new one
+		option.Logger, _ = logger.NewTmpLogger()
 	}
-	l.Close()
 
-	return &Instance{
+	return &Manager{
 		server:    nil,
 		isRunning: false,
-		option:    &option,
-	}, nil
+		Option:    &option,
+	}
+}
+
+// Interfaces required for registering File Server in ArozOS
+func (s *Manager) IsRunning() bool {
+	return s.isRunning
+}
+
+func (s *Manager) GetEndpoints(userinfo *user.User) []*fileservers.Endpoint {
+	eps := []*fileservers.Endpoint{}
+	eps = append(eps, &fileservers.Endpoint{
+		ProtocolName: "\\\\",
+		Port:         s.Option.ListeningPort,
+		Subpath:      "",
+	})
+	return eps
+}
+
+func (s *Manager) ServerToggle(enabled bool) error {
+	if s.isRunning {
+		return s.Stop()
+	} else {
+		return s.Start()
+	}
+}
+
+// Wrapper for logger PrintAndLog
+func (s *Manager) Log(message string, err error) {
+	s.Option.Logger.PrintAndLog("NFS", message, err)
+}
+
+// TODO: Link this to arozfs
+func (s *Manager) Start() error {
+	mfs := memfs.NewMemFS()
+	backend := backend.New(mfs)
+	svr, err := server.NewServerTCP(":"+strconv.Itoa(s.Option.ListeningPort), backend)
+	if err != nil {
+		s.Log("failed to start NFS Server", err)
+		return err
+	}
+	s.Log("Server started listening on "+":"+strconv.Itoa(s.Option.ListeningPort), nil)
+	s.server = svr
+	s.isRunning = true
+	go func() {
+		if err := svr.Serve(); err != nil {
+			fmt.Printf("svr.Serve: %v\n", err)
+		}
+	}()
+	return nil
+}
+
+func (s *Manager) Stop() error {
+
+	return nil
 }

+ 104 - 93
mod/info/logger/logger.go

@@ -1,93 +1,104 @@
-package logger
-
-import (
-	"fmt"
-	"log"
-	"os"
-	"path/filepath"
-	"strconv"
-	"time"
-)
-
-/*
-	ArozOS System Logger
-
-	This script is designed to make a managed log for the ArozOS system
-	and replace the ton of log.Println in the system core
-*/
-
-type Logger struct {
-	LogToFile      bool   //Set enable write to file
-	Prefix         string //Prefix for log files
-	LogFolder      string //Folder to store the log  file
-	CurrentLogFile string //Current writing filename
-	file           *os.File
-}
-
-func NewLogger(logFilePrefix string, logFolder string, logToFile bool) (*Logger, error) {
-	err := os.MkdirAll(logFolder, 0775)
-	if err != nil {
-		return nil, err
-	}
-
-	thisLogger := Logger{
-		LogToFile: logToFile,
-		Prefix:    logFilePrefix,
-		LogFolder: logFolder,
-	}
-
-	logFilePath := thisLogger.getLogFilepath()
-	f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
-	if err != nil {
-		return nil, err
-	}
-	thisLogger.CurrentLogFile = logFilePath
-	thisLogger.file = f
-	return &thisLogger, nil
-}
-
-func (l *Logger) getLogFilepath() string {
-	year, month, _ := time.Now().Date()
-	return filepath.Join(l.LogFolder, l.Prefix+"_"+strconv.Itoa(year)+"-"+strconv.Itoa(int(month))+".log")
-}
-
-//PrintAndLog will log the message to file and print the log to STDOUT
-func (l *Logger) PrintAndLog(title string, message string, originalError error) {
-	go func() {
-		l.Log(title, message, originalError)
-	}()
-	log.Println("[" + title + "] " + message)
-}
-
-func (l *Logger) Log(title string, errorMessage string, originalError error) {
-	l.ValidateAndUpdateLogFilepath()
-	if l.LogToFile {
-		if originalError == nil {
-			l.file.WriteString(time.Now().Format("2006-01-02 15:04:05.000000") + "|" + fmt.Sprintf("%-16s", title) + " [INFO]" + errorMessage + "\n")
-		} else {
-			l.file.WriteString(time.Now().Format("2006-01-02 15:04:05.000000") + "|" + fmt.Sprintf("%-16s", title) + " [ERROR]" + errorMessage + " " + originalError.Error() + "\n")
-		}
-	}
-
-}
-
-//Validate if the logging target is still valid (detect any months change)
-func (l *Logger) ValidateAndUpdateLogFilepath() {
-	expectedCurrentLogFilepath := l.getLogFilepath()
-	if l.CurrentLogFile != expectedCurrentLogFilepath {
-		//Change of month. Update to a new log file
-		l.file.Close()
-		f, err := os.OpenFile(expectedCurrentLogFilepath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
-		if err != nil {
-			log.Println("[Logger] Unable to create new log. Logging to file disabled.")
-			l.LogToFile = false
-			return
-		}
-		l.CurrentLogFile = expectedCurrentLogFilepath
-		l.file = f
-	}
-}
-
-func (l *Logger) Close() {
-	l.file.Close()
-}
+package logger
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"strconv"
+	"time"
+)
+
+/*
+	ArozOS System Logger
+
+	This script is designed to make a managed log for the ArozOS system
+	and replace the ton of log.Println in the system core
+*/
+
+type Logger struct {
+	LogToFile      bool     //Set enable write to file
+	Prefix         string   //Prefix for log files
+	LogFolder      string   //Folder to store the log  file
+	CurrentLogFile string   //Current writing filename
+	file           *os.File //File, empty if LogToFile is false
+}
+
+// Create a default logger
+func NewLogger(logFilePrefix string, logFolder string, logToFile bool) (*Logger, error) {
+	if logToFile {
+		err := os.MkdirAll(logFolder, 0775)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	thisLogger := Logger{
+		LogToFile: logToFile,
+		Prefix:    logFilePrefix,
+		LogFolder: logFolder,
+	}
+
+	if logToFile {
+		logFilePath := thisLogger.getLogFilepath()
+		f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
+		if err != nil {
+			return nil, err
+		}
+		thisLogger.CurrentLogFile = logFilePath
+		thisLogger.file = f
+	}
+
+	return &thisLogger, nil
+}
+
+// Create a non-persistent logger for one-time uses
+func NewTmpLogger() (*Logger, error) {
+	return NewLogger("", "", false)
+}
+
+func (l *Logger) getLogFilepath() string {
+	year, month, _ := time.Now().Date()
+	return filepath.Join(l.LogFolder, l.Prefix+"_"+strconv.Itoa(year)+"-"+strconv.Itoa(int(month))+".log")
+}
+
+// PrintAndLog will log the message to file and print the log to STDOUT
+func (l *Logger) PrintAndLog(title string, message string, originalError error) {
+	go func() {
+		l.Log(title, message, originalError)
+	}()
+	log.Println("[" + title + "] " + message)
+}
+
+func (l *Logger) Log(title string, errorMessage string, originalError error) {
+	if l.LogToFile {
+		l.ValidateAndUpdateLogFilepath()
+		if originalError == nil {
+			l.file.WriteString(time.Now().Format("2006-01-02 15:04:05.000000") + "|" + fmt.Sprintf("%-16s", title) + " [INFO]" + errorMessage + "\n")
+		} else {
+			l.file.WriteString(time.Now().Format("2006-01-02 15:04:05.000000") + "|" + fmt.Sprintf("%-16s", title) + " [ERROR]" + errorMessage + " " + originalError.Error() + "\n")
+		}
+	}
+
+}
+
+// Validate if the logging target is still valid (detect any months change)
+func (l *Logger) ValidateAndUpdateLogFilepath() {
+	expectedCurrentLogFilepath := l.getLogFilepath()
+	if l.CurrentLogFile != expectedCurrentLogFilepath {
+		//Change of month. Update to a new log file
+		l.file.Close()
+		f, err := os.OpenFile(expectedCurrentLogFilepath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
+		if err != nil {
+			log.Println("[Logger] Unable to create new log. Logging to file disabled.")
+			l.LogToFile = false
+			return
+		}
+		l.CurrentLogFile = expectedCurrentLogFilepath
+		l.file = f
+	}
+}
+
+func (l *Logger) Close() {
+	l.file.Close()
+}

+ 211 - 0
mod/storage/billyconv/billyconv.go

@@ -0,0 +1,211 @@
+package billyconv
+
+/*
+	Billy Filesystem Converter
+
+	This module converts an arozfs file system into a Billy Filesystem
+	used by many other projects for providing a vfs interface
+*/
+import (
+	"errors"
+	"io/fs"
+	"os"
+	"path/filepath"
+
+	"github.com/go-git/go-billy/v5"
+	"imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/filesystem/arozfs"
+)
+
+//This script adapts the required billy.FileSystem to arozos abstraction
+
+type ArozFsToBillyFileSytemAdapter struct {
+	fsh *filesystem.FileSystemHandler
+}
+
+func NewArozFsToBillyFsAdapter(targetFsh *filesystem.FileSystemHandler) billy.Filesystem {
+	return &ArozFsToBillyFileSytemAdapter{
+		fsh: targetFsh,
+	}
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) Create(filename string) (billy.File, error) {
+	filename = adp.CleanAndFilterFilename(filename)
+	file, err := adp.fsh.FileSystemAbstraction.Create(filename)
+	if err != nil {
+		return nil, err
+	}
+	return ArozfsFileToBillyFile(file), nil
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) Open(filename string) (billy.File, error) {
+	filename = adp.CleanAndFilterFilename(filename)
+	file, err := adp.fsh.FileSystemAbstraction.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	return ArozfsFileToBillyFile(file), nil
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) OpenFile(filename string, flag int, perm os.FileMode) (billy.File, error) {
+	filename = adp.CleanAndFilterFilename(filename)
+	file, err := adp.fsh.FileSystemAbstraction.OpenFile(filename, flag, perm)
+	if err != nil {
+		return nil, err
+	}
+	return ArozfsFileToBillyFile(file), nil
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) Stat(filename string) (os.FileInfo, error) {
+	filename = adp.CleanAndFilterFilename(filename)
+	fileInfo, err := adp.fsh.FileSystemAbstraction.Stat(filename)
+	if err != nil {
+		return nil, err
+	}
+	return ConvertToOsFileInfo(fileInfo), err
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) Rename(oldpath, newpath string) error {
+	oldpath = adp.CleanAndFilterFilename(oldpath)
+	newpath = adp.CleanAndFilterFilename(newpath)
+	return adp.Rename(oldpath, newpath)
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) Remove(filename string) error {
+	filename = adp.CleanAndFilterFilename(filename)
+	return adp.fsh.FileSystemAbstraction.Remove(filename)
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) Join(elem ...string) string {
+	return filepath.Join(elem...)
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) TempFile(dir, prefix string) (billy.File, error) {
+	return nil, errors.New("operation not supported")
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) ReadDir(path string) ([]os.FileInfo, error) {
+	path = adp.CleanAndFilterFilename(path)
+	dirEntry, err := adp.fsh.FileSystemAbstraction.ReadDir(path)
+	if err != nil {
+		return []os.FileInfo{}, err
+	}
+
+	fileInfo, err := ConvertDirEntriesToFileInfos(dirEntry)
+	if err != nil {
+		return []os.FileInfo{}, err
+	}
+
+	return fileInfo, nil
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) MkdirAll(filename string, perm os.FileMode) error {
+	filename = adp.CleanAndFilterFilename(filename)
+	return adp.fsh.FileSystemAbstraction.MkdirAll(filename, perm)
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) Lstat(filename string) (os.FileInfo, error) {
+	return nil, errors.New("operation not supported")
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) Symlink(target, link string) error {
+	return errors.New("operation not supported")
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) Readlink(link string) (string, error) {
+	return "", errors.New("operation not supported")
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) Chroot(path string) (billy.Filesystem, error) {
+	return nil, errors.New("operation not supported")
+}
+
+func (adp *ArozFsToBillyFileSytemAdapter) Root() string {
+	return "/"
+}
+
+/* Utilities */
+func (adp *ArozFsToBillyFileSytemAdapter) CleanAndFilterFilename(filename string) string {
+	return filename
+}
+
+/*
+arozfs.File to Billy.File converter
+*/
+type ArozFSFileAdapter struct {
+	file arozfs.File
+}
+
+func ArozfsFileToBillyFile(file arozfs.File) billy.File {
+	return &ArozFSFileAdapter{
+		file: file,
+	}
+}
+
+func (afa *ArozFSFileAdapter) Name() string {
+	return afa.file.Name()
+}
+
+func (afa *ArozFSFileAdapter) Read(b []byte) (int, error) {
+	return afa.file.Read(b)
+}
+
+func (afa *ArozFSFileAdapter) ReadAt(b []byte, off int64) (int, error) {
+	return afa.file.ReadAt(b, off)
+}
+
+func (afa *ArozFSFileAdapter) Seek(offset int64, whence int) (int64, error) {
+	return afa.file.Seek(offset, whence)
+}
+
+func (afa *ArozFSFileAdapter) Write(b []byte) (int, error) {
+	return afa.file.Write(b)
+}
+
+func (afa *ArozFSFileAdapter) Lock() error {
+	return nil
+}
+
+func (afa *ArozFSFileAdapter) Unlock() error {
+	return nil
+}
+
+func (afa *ArozFSFileAdapter) Truncate(size int64) error {
+	return errors.New("operation not supported")
+}
+
+func (afa *ArozFSFileAdapter) Close() error {
+	return afa.file.Close()
+}
+
+/*
+
+ */
+
+// Define a type that wraps an fs.FileInfo and implements os.FileInfo
+type fileInfoWrapper struct {
+	fs.FileInfo
+}
+
+// Implement the Sys method to satisfy os.FileInfo
+func (f fileInfoWrapper) Sys() interface{} {
+	return nil
+}
+
+// Convert fs.FileInfo to os.FileInfo
+func ConvertToOsFileInfo(fi fs.FileInfo) os.FileInfo {
+	return fileInfoWrapper{fi}
+}
+
+// Convert []fs.DirEntry to []os.FileInfo
+func ConvertDirEntriesToFileInfos(entries []fs.DirEntry) ([]os.FileInfo, error) {
+	var fileInfos []os.FileInfo
+	for _, entry := range entries {
+		info, err := entry.Info()
+		if err != nil {
+			return nil, err
+		}
+		fileInfos = append(fileInfos, ConvertToOsFileInfo(info))
+	}
+	return fileInfos, nil
+}

+ 20 - 1
network.go

@@ -2,6 +2,7 @@ package main
 
 import (
 	"encoding/json"
+	"fmt"
 	"net/http"
 	"strconv"
 	"strings"
@@ -9,6 +10,7 @@ import (
 	"imuslab.com/arozos/mod/fileservers"
 	"imuslab.com/arozos/mod/fileservers/servers/dirserv"
 	"imuslab.com/arozos/mod/fileservers/servers/ftpserv"
+	"imuslab.com/arozos/mod/fileservers/servers/nfsserv"
 	"imuslab.com/arozos/mod/fileservers/servers/sftpserv"
 	"imuslab.com/arozos/mod/fileservers/servers/webdavserv"
 	network "imuslab.com/arozos/mod/network"
@@ -17,6 +19,7 @@ import (
 	ssdp "imuslab.com/arozos/mod/network/ssdp"
 	upnp "imuslab.com/arozos/mod/network/upnp"
 	"imuslab.com/arozos/mod/network/websocket"
+	"imuslab.com/arozos/mod/permission"
 	prout "imuslab.com/arozos/mod/prouter"
 	"imuslab.com/arozos/mod/utils"
 	"imuslab.com/arozos/mod/www"
@@ -33,6 +36,7 @@ var (
 	FTPManager     *ftpserv.Manager
 	WebDAVManager  *webdavserv.Manager
 	SFTPManager    *sftpserv.Manager
+	NFSManager     *nfsserv.Manager
 	DirListManager *dirserv.Manager
 )
 
@@ -275,7 +279,8 @@ func FileServerInit() {
 		},
 	})
 
-	//Create File Server Managers
+	/* Create File Server Managers */
+	//WebDAV
 	webdavPort := *listen_port
 	if *use_tls {
 		webdavPort = *tls_listen_port
@@ -289,6 +294,7 @@ func FileServerInit() {
 		UserHandler: userHandler,
 	})
 
+	//FTP
 	FTPManager = ftpserv.NewFTPManager(&ftpserv.ManagerOption{
 		Hostname:    *host_name,
 		TmpFolder:   *tmp_directory,
@@ -300,6 +306,7 @@ func FileServerInit() {
 		AllowUpnp:   *allow_upnp,
 	})
 
+	//SFTP
 	SFTPManager = sftpserv.NewSFTPServer(&sftpserv.ManagerOption{
 		Hostname:    *host_name,
 		Upnp:        UPNP,
@@ -320,6 +327,18 @@ func FileServerInit() {
 		ServerUUID:  deviceUUID,
 	})
 
+	//NFS
+	NFSManager = nfsserv.NewNfsServer(nfsserv.Option{
+		UserManager:      userHandler,
+		ListeningPort:    2049,
+		AllowAccessGroup: []*permission.PermissionGroup{},
+		Logger:           nil,
+	})
+	err := NFSManager.Start()
+	if err != nil {
+		fmt.Println(err.Error())
+	}
+
 	//Register Endpoints
 	//WebDAV
 	http.HandleFunc("/system/network/webdav/list", WebDAVManager.HandleConnectionList)