Selaa lähdekoodia

Utils to parse -o options

Cleaned logging, added extra verbose flag
luis 7 vuotta sitten
vanhempi
commit
6192c65262

+ 76 - 39
README.md

@@ -1,13 +1,29 @@
 cloudmount
 =====================
-
 Linux util to Mount cloud drives
 
-####Usage:
+**Table of Contents**
+
+- [Installation](#installation)
+- [Usage](#usage)
+- [Example](#example)
+- [Cloud services](#cloud-services)
+  - [Google drive](#google-drive)
+  - [Dropbox](#dropbox)
+- [Signals](#signals)
+
+<a name="installation"></a>
+#### Installation
+```bash
+$ go get dev.hexasoftware.com/hxs/cloudmount
+```
+
+<a name="usage"></a>
+#### Usage
 ```bash
 $ cloudmount -h
 
-cloudmount-0.3-3-gadf4880 - built: 2017-07-11 01:34:58 UTC
+cloudmount-0.4-5-gf01e8fb - built: 2017-07-17 05:09:51 UTC
 
 Usage: cloudmount [options] [<source>] <directory>
 
@@ -16,35 +32,40 @@ Source: can be json/yaml configuration file usually with credentials or cloud sp
 Options:
   -d	Run app in background
   -o string
-    	uid,gid ex: -o uid=1000,gid=0 
+    	uid=1000,gid=1000,ro=false
   -r duration
-    	Timed cloud synchronization interval [if applied] (default 2m0s)
+    	Timed cloud synchronization interval [if applied] (default 5s)
   -t string
     	which cloud service to use [gdrive] (default "gdrive")
   -v	Verbose log
+  -vv
+    	Extra Verbose log
   -w string
-    	Work dir, path that holds configurations (default "<homedir>/.cloudmount")
-```
+    	Work dir, path that holds configurations (default "$HOME/.cloudmount")
 
-
-#### Example:
+```
+<a name="example"></a>
+#### Example
 ```bash
-$ go get dev.hexasoftware.com/hxs/cloudmount
-# will default source file to $HOME/.cloudmount/gdrive.json
-$ cloudmount MOUNTPOINT
+# will default source file to $HOME/.cloudmount/gdrive.yaml
+$ cloudmount -t gdrive /mnt/gdrive
 # or 
-$ cloudmount gdrive.json MOUNTPOINT
-
+$ cloudmount -t dropbox dropbox.yaml /mnt/gdrive
 ```
-#### Source config:
-Configuration files/source can be written in following formats:
-* json
+
+**Source config**
+Configuration files/source can be written in following formats:   
 * yaml
+* json
 
-#### Support for:
+<a name="cloud-services"></a>
+#### Cloud services
 * Google Drive
+* Dropbox
 
+--------------
 
+<a name="google-drive"></a>
 ### Google Drive
 
 Setup Google client secrets:
@@ -60,46 +81,62 @@ https://console.developers.google.com/apis/credentials
 >	5. Select the application type Other, enter the name "Drive API Quickstart", and click the Create button.
 >	6. With the result dialog, copy clientID and client secret and create json file as shown in example (this can be retrieved any time by clicking on the api key)
 
-sample *gdrive.json* config:    
-```json
-{
-  "client_secret": {
-   "client_id": "CLIENTID",
-   "client_secret": "CLIENTSECRET"
-  }
-}
-```
-or yaml format:
+sample _gdrive.yaml_ config:    
 ```yaml
 client_secret:
-  client_id: CLIENTID
-  client_secret: CLIENTSECRET
+  client_id: *Client ID*
+  client_secret: *Client Secret*
 ```
-
 ```bash
-$ cloudmount gdrive.json $HOME/mntpoint
+$ cloudmount gdrive.yaml $HOME/mntpoint
 ```
 
-Also it's possible to create the json/yaml file in home directory as 
-__$HOME/.cloudmount/gdrive.json__
-if &lt;source&gt; parameter is ommited it will default to this file
-
+Also it's possible to create the yaml file in home directory as 
+__$HOME/.cloudmount/gdrive.yaml__
+if &lt;source&gt; parameter is omitted it will default to this file
 
 cloudmount gdrivefs will retrieve an oauth2 token and save in same file
 
 
+<a name="dropbox"></a>
+### Dropbox
+
+Setup Dropbox client secrets:
+
+https://www.dropbox.com/developers/apps
+
+> 1. Click _Create App_ 
+> 2. Select the API, type of access, and App name 
+> 3. Use the values from _App key_ and _App secret_
+
+sample _dropbox.yaml_ file:
+```yaml
+client_secret:
+  client_id: *App Key*
+  client_secret: *App secret*
+
+```
+
+```bash
+$ cloudmount -t dropbox savedfile.yaml /mnt/point
+```
+
+On the first run a link will appear and it will request a token resuling from the link
+
+--------------------
 
 #### Signals
 Signal | Action                                                                                               | ex
 -------|------------------------------------------------------------------------------------------------------|-----------------
-USR1   | Refreshes directory tree from file system                                                            | killall -USR1 gdrivemount
-HUP    | Perform a GC and shows memory usage <small>Works when its not running in daemon mode</small>         | killall -HUP gdrivemount
+USR1   | Refreshes directory tree from file system                                                            | killall -USR1 cloudmount
+HUP    | Perform a GC and shows memory usage <small>Works when its not running in daemon mode</small>         | killall -HUP cloudmount
 
 
 
 #### TODO & IDEAS:
 * Consider using github.com/codegangsta/cli
 * Create test suit to implement new packages
-* GDrive: long term caching, maintain most used files locally until flush/change
+* Caching: long term caching, maintain most used files locally until flush/change
+
 
 

+ 0 - 30
SPEC.md

@@ -1,30 +0,0 @@
-
-
-
-Fuse Interface -> File container -> Service (produces File)
-
-
-Package structure
-
-
-cloudfs/ core package
-
-fs/gdrivefs  
- * Init check configuration
- * Fetch FuseHandler
-
-
-Make usage something like this:
-
-```bash
-	cloudfs source.json destfolder
-
-```
-
-
-Core should not care about flags, only config
-
-main should care about flags
-
-
-

+ 3 - 3
TODO.md

@@ -1,13 +1,13 @@
 #### TODO:   
-* Safemode flag not needed i supose 
-* Add verbosity levels (sometimes just want to log the driver and not fuse)
 * Create test cases
-* Create and reference dropbox oauth doc
 * Remove default gdrive and determine fs by arg[0] when possible
 	* cloudmount.gdrive will mount gdrive
 	* cloudmount.dropbox ..
 
 #### Done:   
+* Create and reference dropbox oauth doc
+* Add verbosity levels (sometimes just want to log the driver and not fuse)
+* Safemode flag not needed i supose 
 * move client from fs's to service.go
 * Sanitize error on basefs, file_container produces err, basefs produces fuse.E..
 

+ 26 - 32
flags.go

@@ -6,10 +6,9 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
-	"strconv"
-	"strings"
 
 	"dev.hexasoftware.com/hxs/cloudmount/internal/core"
+	"dev.hexasoftware.com/hxs/cloudmount/internal/coreutil"
 )
 
 func parseFlags(config *core.Config) (err error) {
@@ -18,10 +17,11 @@ func parseFlags(config *core.Config) (err error) {
 	flag.StringVar(&config.Type, "t", config.Type, "which cloud service to use [gdrive]")
 	flag.BoolVar(&config.Daemonize, "d", false, "Run app in background")
 	flag.BoolVar(&config.VerboseLog, "v", false, "Verbose log")
+	flag.BoolVar(&config.Verbose2Log, "vv", false, "Extra Verbose log")
 	flag.StringVar(&config.HomeDir, "w", config.HomeDir, "Work dir, path that holds configurations")
 	flag.DurationVar(&config.RefreshTime, "r", config.RefreshTime, "Timed cloud synchronization interval [if applied]")
 
-	flag.StringVar(&mountoptsFlag, "o", "", "uid,gid,safemode ex: -o uid=1000,gid=0")
+	flag.StringVar(&mountoptsFlag, "o", "", fmt.Sprintf("%v", config.Options))
 
 	flag.Usage = func() {
 		fmt.Fprintf(os.Stderr, "\n")
@@ -33,6 +33,11 @@ func parseFlags(config *core.Config) (err error) {
 	}
 	flag.Parse()
 
+	fileExt := filepath.Ext(os.Args[0])
+	if fileExt != "" {
+		config.Type = fileExt[1:]
+	}
+
 	if flag.NArg() < 1 {
 		flag.Usage()
 		//fmt.Println("Usage:\n gdrivemount [-d] [-v] <SRC/CONFIG> <MOUNTPOINT>")
@@ -45,41 +50,30 @@ func parseFlags(config *core.Config) (err error) {
 		config.Source = flag.Arg(0)
 		config.Target = flag.Arg(1)
 	}
-	/////////////////////////////////////
-	// Parse mount opts
-	/////////////////
-	pmountopts := strings.Split(mountoptsFlag, ",")
-	mountopts := map[string]string{}
-	for _, v := range pmountopts {
-		if keyindex := strings.Index(v, "="); keyindex != -1 {
-			key := strings.TrimSpace(v[:keyindex])
-			value := strings.TrimSpace(v[keyindex+1:])
-			mountopts[key] = value
-		}
+
+	if config.Verbose2Log {
+		config.VerboseLog = true
 	}
 
-	/////////////////////////////////////
-	// Use mount opts
-	///////////////
-	uidStr, ok := mountopts["uid"]
-	if ok {
-		uid, err := strconv.Atoi(uidStr)
-		if err != nil {
-			panic(err)
+	// Read fs type from config file
+	sourceType := struct {
+		Type string `json:"type"`
+	}{}
+	coreutil.ParseConfig(config.Source, &sourceType)
+	if sourceType.Type != "" {
+		if config.Type != "" && sourceType.Type != config.Type {
+			log.Fatalf("ERR: service mismatch <source> specifies '%s' while flag -t is '%s'", sourceType.Type, config.Type)
 		}
-		config.UID = uint32(uid)
+		config.Type = sourceType.Type
 	}
 
-	gidStr, ok := mountopts["gid"]
-	if ok {
-		gid, err := strconv.Atoi(gidStr)
-		if err != nil {
-			panic(err)
-		}
-		config.GID = uint32(gid)
+	if config.Type == "" {
+		log.Fatalf("ERR: Missing -t param, unknown file system")
 	}
-	if mountopts["safemode"] == "true" {
-		config.Safemode = true
+
+	err = coreutil.ParseOptions(mountoptsFlag, &config.Options)
+	if err != nil {
+		log.Fatal("ERR: Invalid syntax parsing mount options")
 	}
 	return
 }

+ 24 - 6
internal/core/config.go

@@ -1,20 +1,38 @@
 package core
 
-import "time"
+import (
+	"time"
+
+	"dev.hexasoftware.com/hxs/cloudmount/internal/coreutil"
+)
 
 // Config struct
 type Config struct {
 	Daemonize   bool
 	Type        string
 	VerboseLog  bool
+	Verbose2Log bool
 	RefreshTime time.Duration
 	HomeDir     string
-	UID         uint32 // Mount UID
-	GID         uint32 // Mount GID
 	Target      string // should be a folder
 	Source      string
-	Safemode    bool
 
-	// Driver specific params:
-	Param map[string]interface{}
+	//Options map[string]string
+	Options Options
+}
+
+// Options are specified in cloudmount -o option1=1, option2=2
+type Options struct { // are Options for specific driver?
+	// Sub options
+	UID      uint32 `opt:"uid"`
+	GID      uint32 `opt:"gid"` // Mount GID
+	Readonly bool   `opt:"ro"`
+}
+
+func (o Options) String() string {
+	return coreutil.OptionString(o)
+}
+func (o Options) ToMap() map[string]string {
+	// Convert to map
+	return map[string]string{}
 }

+ 39 - 16
internal/core/core.go

@@ -3,15 +3,16 @@ package core
 import (
 	"context"
 	"flag"
+	glog "log"
 	"os"
 	"os/signal"
 	"os/user"
 	"path/filepath"
 	"runtime"
-	"strconv"
 	"syscall"
 	"time"
 
+	"dev.hexasoftware.com/hxs/cloudmount/internal/coreutil"
 	"dev.hexasoftware.com/hxs/prettylog"
 
 	"github.com/jacobsa/fuse"
@@ -19,7 +20,9 @@ import (
 )
 
 var (
-	log = prettylog.New("cloudmount")
+	pname  = "cloudmount"
+	log    = prettylog.Dummy()
+	errlog = prettylog.New(pname + "-err")
 )
 
 // Core struct
@@ -39,28 +42,32 @@ func New() *Core {
 		panic(err)
 	}
 
-	uid, err := strconv.Atoi(usr.Uid)
+	var uid, gid uint32
+	err = coreutil.StringAssign(usr.Uid, &uid)
 	if err != nil {
 		panic(err)
 	}
-	gid, err := strconv.Atoi(usr.Gid)
+	err = coreutil.StringAssign(usr.Gid, &gid)
 	if err != nil {
-		panic(gid)
+		panic(err)
 	}
 
 	return &Core{
 		Drivers: map[string]DriverFactory{},
 		Config: Config{
 			Daemonize:   false,
-			Type:        "gdrive",
+			Type:        "",
 			VerboseLog:  false,
 			RefreshTime: 5 * time.Second,
 			HomeDir:     filepath.Join(usr.HomeDir, ".cloudmount"),
 			Source:      filepath.Join(usr.HomeDir, ".cloudmount", "gdrive.yaml"),
 
-			Safemode: false,
-			UID:      uint32(uid),
-			GID:      uint32(gid),
+			// Defaults at least
+			Options: Options{
+				UID:      uint32(uid),
+				GID:      uint32(gid),
+				Readonly: false,
+			},
 		},
 	}
 
@@ -69,9 +76,13 @@ func New() *Core {
 // Init to be run after configuration
 func (c *Core) Init() (err error) {
 
+	if c.Config.VerboseLog {
+		log = prettylog.New(pname)
+	}
+
 	fsFactory, ok := c.Drivers[c.Config.Type]
 	if !ok {
-		log.Fatal("CloudFS not supported")
+		errlog.Fatal("CloudFS not supported")
 	}
 
 	c.CurrentFS = fsFactory(c) // Factory
@@ -93,13 +104,25 @@ func (c *Core) Mount() {
 	var err error
 	var mfs *fuse.MountedFileSystem
 
-	if c.Config.VerboseLog {
-		mfs, err = fuse.Mount(mountPath, server, &fuse.MountConfig{DebugLogger: prettylog.New("fuse"), ErrorLogger: prettylog.New("fuse-err")})
-	} else {
-		mfs, err = fuse.Mount(mountPath, server, &fuse.MountConfig{})
+	fsname := c.Config.Source
+
+	var dbgLogger *glog.Logger
+	var errLogger *glog.Logger
+	if c.Config.Verbose2Log { // Extra verbose
+		dbgLogger = prettylog.New("fuse")
+		errLogger = prettylog.New("fuse-err")
 	}
+
+	mfs, err = fuse.Mount(mountPath, server, &fuse.MountConfig{
+		VolumeName: "cloudmount",
+		//Options:     coreutil.OptionMap(c.Config.Options),
+		FSName:      fsname,
+		DebugLogger: dbgLogger,
+		ErrorLogger: errLogger,
+		ReadOnly:    c.Config.Options.Readonly,
+	})
 	if err != nil {
-		log.Fatal("Failed mounting path", flag.Arg(0), err)
+		errlog.Fatal("Failed mounting path ", flag.Arg(0), err)
 	}
 
 	// Signal handling to refresh Drives
@@ -136,7 +159,7 @@ func (c *Core) Mount() {
 	}()
 
 	if err := mfs.Join(ctx); err != nil {
-		log.Fatalf("Joining: %v", err)
+		errlog.Fatalf("Joining: %v", err)
 	}
 
 }

+ 0 - 64
internal/core/util.go

@@ -1,64 +0,0 @@
-package core
-
-import (
-	"encoding/json"
-	"io/ioutil"
-	"os"
-	"strings"
-
-	"github.com/go-yaml/yaml"
-)
-
-// ParseConfig, reads yaml or json file into a struct
-func ParseConfig(srcfile string, out interface{}) (err error) {
-	if srcfile == "" {
-		return
-	}
-	f, err := os.Open(srcfile)
-	if err != nil {
-		return err
-	}
-	defer f.Close()
-
-	if strings.HasSuffix(srcfile, ".json") {
-		// Read as JSON
-		json.NewDecoder(f).Decode(out)
-		return
-	}
-	if strings.HasSuffix(srcfile, ".yaml") {
-		data, err := ioutil.ReadAll(f)
-		if err != nil {
-			return err
-		}
-		// Read as yaml
-		yaml.Unmarshal(data, out)
-	}
-	return err
-}
-
-func SaveConfig(name string, obj interface{}) (err error) {
-	var data []byte
-	if strings.HasSuffix(name, ".json") {
-		data, err = json.MarshalIndent(obj, "  ", "  ")
-		if err != nil {
-			return err
-		}
-	}
-	if strings.HasSuffix(name, ".yaml") {
-		data, err = yaml.Marshal(obj)
-		if err != nil {
-			return err
-		}
-	}
-
-	f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
-	if err != nil {
-		log.Fatalf("Unable to save config: %v\n", err)
-	}
-	defer f.Close()
-
-	f.Write(data)
-	f.Sync()
-
-	return err
-}

+ 186 - 0
internal/coreutil/util.go

@@ -0,0 +1,186 @@
+package coreutil
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"reflect"
+	"strconv"
+	"strings"
+
+	"github.com/go-yaml/yaml"
+)
+
+// ParseConfig, reads yaml or json file into a struct
+func ParseConfig(srcfile string, out interface{}) (err error) {
+	if srcfile == "" {
+		return
+	}
+	f, err := os.Open(srcfile)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	if strings.HasSuffix(srcfile, ".json") {
+		// Read as JSON
+		json.NewDecoder(f).Decode(out)
+		return
+	}
+	if strings.HasSuffix(srcfile, ".yaml") {
+		data, err := ioutil.ReadAll(f)
+		if err != nil {
+			return err
+		}
+		// Read as yaml
+		yaml.Unmarshal(data, out)
+	}
+	return err
+}
+
+func SaveConfig(name string, obj interface{}) (err error) {
+	var data []byte
+	if strings.HasSuffix(name, ".json") {
+		data, err = json.MarshalIndent(obj, "  ", "  ")
+		if err != nil {
+			return err
+		}
+	}
+	if strings.HasSuffix(name, ".yaml") {
+		data, err = yaml.Marshal(obj)
+		if err != nil {
+			return err
+		}
+	}
+
+	f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
+	if err != nil {
+		log.Fatalf("Unable to save config: %v\n", err)
+	}
+	defer f.Close()
+
+	f.Write(data)
+	f.Sync()
+
+	return err
+}
+
+// ParseOptions parses mount options like -o uid=100,gid=100 to struct
+func ParseOptions(opt string, out interface{}) (err error) {
+	mountopts := map[string]string{}
+	parts := strings.Split(opt, ",")
+	// First Map to keyvalue
+	for _, v := range parts {
+		if keyindex := strings.Index(v, "="); keyindex != -1 { // Eq
+			key := strings.TrimSpace(v[:keyindex])
+			value := strings.TrimSpace(v[keyindex+1:])
+			mountopts[key] = value
+		} else {
+			mountopts[v] = "true"
+		}
+	}
+
+	// Assign map to object by Tag by iterating fields
+	typ := reflect.TypeOf(out).Elem() // Should be pointer
+	val := reflect.ValueOf(out).Elem()
+	for i := 0; i < typ.NumField(); i++ {
+		fieldTyp := typ.Field(i)
+		fieldVal := val.Field(i)
+		name := strings.ToLower(fieldTyp.Name)
+		if tag, ok := fieldTyp.Tag.Lookup("opt"); ok {
+			tagParts := strings.Split(tag, ",")
+			if len(tagParts) > 0 && tagParts[0] != "" {
+				name = tagParts[0]
+			}
+		}
+
+		if v, ok := mountopts[name]; ok {
+			err = StringAssign(v, fieldVal.Addr().Interface())
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return
+}
+
+// StringAssign parseString and place value in
+func StringAssign(s string, v interface{}) (err error) {
+	val := reflect.ValueOf(v).Elem()
+	switch val.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: // More values
+		parsed, err := strconv.ParseInt(s, 10, 64)
+		if err != nil {
+			return err
+		}
+		sval := reflect.ValueOf(parsed)
+		val.Set(sval.Convert(val.Type()))
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: // More values
+		parsed, err := strconv.ParseUint(s, 10, 64)
+		if err != nil {
+			return err
+		}
+		sval := reflect.ValueOf(parsed)
+		val.Set(sval.Convert(val.Type()))
+	case reflect.Bool:
+		parsed, err := strconv.ParseBool(s)
+		if err != nil {
+			return err
+		}
+		sval := reflect.ValueOf(parsed)
+		val.Set(sval)
+	}
+
+	return
+}
+
+func OptionString(o interface{}) string {
+	ret := ""
+	typ := reflect.TypeOf(o) // Should be pointer
+	val := reflect.ValueOf(o)
+	for i := 0; i < typ.NumField(); i++ {
+		fieldTyp := typ.Field(i)
+		fieldVal := val.Field(i)
+		name := strings.ToLower(fieldTyp.Name)
+		desc := ""
+		if tag, ok := fieldTyp.Tag.Lookup("opt"); ok {
+			tagParts := strings.Split(tag, ",")
+			if len(tagParts) > 0 && tagParts[0] != "" {
+				name = tagParts[0]
+			}
+			/*if len(tagParts) >= 2 {
+				desc = tagParts[1]
+			}*/
+		}
+		if i != 0 {
+			ret += ","
+		}
+		if desc != "" {
+			ret += fmt.Sprintf("%s=%v (%s)", name, fieldVal.Interface(), desc)
+		} else {
+			ret += fmt.Sprintf("%s=%v", name, fieldVal.Interface())
+		}
+	}
+
+	return ret
+}
+func OptionMap(o interface{}) map[string]string {
+	ret := map[string]string{}
+	typ := reflect.TypeOf(o) // Should be pointer
+	val := reflect.ValueOf(o)
+	for i := 0; i < typ.NumField(); i++ {
+		fieldTyp := typ.Field(i)
+		fieldVal := val.Field(i)
+		name := strings.ToLower(fieldTyp.Name)
+		if tag, ok := fieldTyp.Tag.Lookup("opt"); ok {
+			tagParts := strings.Split(tag, ",")
+			if len(tagParts) > 0 && tagParts[0] != "" {
+				name = tagParts[0]
+			}
+		}
+		ret[name] = fmt.Sprintf("%v", fieldVal.Interface())
+	}
+	return ret
+}

+ 43 - 17
internal/fs/basefs/basefs.go

@@ -4,8 +4,6 @@ package basefs
 import (
 	"errors"
 	"io"
-	"io/ioutil"
-	glog "log"
 	"math"
 	"os"
 	"sync"
@@ -27,7 +25,9 @@ import (
 const maxInodes = math.MaxUint64
 
 var (
-	log = glog.New(ioutil.Discard, "", 0)
+	pname  = "basefs"
+	log    = prettylog.Dummy()
+	errlog = prettylog.New(pname + "-err")
 	// ErrNotImplemented basic Not implemented error
 	ErrNotImplemented = errors.New("Not implemented")
 	// ErrPermission permission denied error
@@ -56,8 +56,7 @@ type BaseFS struct {
 // New Creates a new BaseFS with config based on core
 func New(core *core.Core) *BaseFS {
 	if core.Config.VerboseLog {
-		log = prettylog.New("basefs")
-
+		log = prettylog.New(pname)
 	}
 
 	fs := &BaseFS{
@@ -67,8 +66,8 @@ func New(core *core.Core) *BaseFS {
 	}
 
 	fs.Root = NewFileContainer(fs)
-	fs.Root.uid = core.Config.UID
-	fs.Root.gid = core.Config.GID
+	fs.Root.uid = fs.Config.Options.UID
+	fs.Root.gid = fs.Config.Options.GID
 
 	loadingFile := File{Name: "Loading...", ID: "0"}
 	entry := fs.Root.FileEntry(&loadingFile, maxInodes) // Last inode
@@ -120,7 +119,8 @@ func (fs *BaseFS) CheckForChanges() {
 			continue
 		}
 		if entry != nil {
-			entry.SetFile(c.File, fs.Config.UID, fs.Config.GID)
+			entry.SetFile(c.File, fs.Config.Options.UID, fs.Config.Options.GID)
+			//entry.SetFile(c.File)
 		} else {
 			//Create new one
 			fs.Root.FileEntry(c.File) // Creating new one
@@ -181,7 +181,7 @@ func (fs *BaseFS) OpenDir(ctx context.Context, op *fuseops.OpenDirOp) (err error
 func (fs *BaseFS) ReadDir(ctx context.Context, op *fuseops.ReadDirOp) (err error) {
 	fh, ok := fs.fileHandles[op.Handle]
 	if !ok {
-		log.Fatal("Handle does not exists")
+		errlog.Fatal("Handle does not exists")
 	}
 
 	if op.Offset == 0 { // Rebuild/rewind dir list
@@ -341,13 +341,16 @@ func (fs *BaseFS) ReadFile(ctx context.Context, op *fuseops.ReadFileOp) (err err
 // CreateFile creates empty file in google Drive and returns its ID and attributes, only allows file creation on 'My Drive'
 // Cloud SPECIFIC
 func (fs *BaseFS) CreateFile(ctx context.Context, op *fuseops.CreateFileOp) (err error) {
+	/*if fs.Config.Options.Readonly {
+		return syscall.EPERM
+	}*/
 
 	parentFile := fs.Root.FindByInode(op.Parent)
 	if parentFile == nil {
 		return fuse.ENOENT
 	}
 	// Only write on child folders
-	if fs.Config.Safemode && parentFile == fs.Root.FileEntries[fuseops.RootInodeID] {
+	if parentFile == fs.Root.FileEntries[fuseops.RootInodeID] {
 		return syscall.EPERM
 	}
 
@@ -385,6 +388,10 @@ func (fs *BaseFS) CreateFile(ctx context.Context, op *fuseops.CreateFileOp) (err
 // Maybe the ReadFile should be called here aswell to cache current contents since we are using writeAt
 // CLOUD SPECIFIC
 func (fs *BaseFS) WriteFile(ctx context.Context, op *fuseops.WriteFileOp) (err error) {
+	/*if fs.Config.Options.Readonly {
+		return syscall.EPERM
+	}*/
+
 	handle, ok := fs.fileHandles[op.Handle]
 	if !ok {
 		return fuse.EIO
@@ -407,6 +414,10 @@ func (fs *BaseFS) WriteFile(ctx context.Context, op *fuseops.WriteFileOp) (err e
 // FlushFile just returns no error, maybe upload should be handled here
 // COMMON
 func (fs *BaseFS) FlushFile(ctx context.Context, op *fuseops.FlushFileOp) (err error) {
+	/*if fs.Config.Options.Readonly {
+		return syscall.EPERM
+	}*/
+
 	handle, ok := fs.fileHandles[op.Handle]
 	if !ok {
 		return fuse.EIO
@@ -438,9 +449,13 @@ func (fs *BaseFS) ReleaseFileHandle(ctx context.Context, op *fuseops.ReleaseFile
 // Unlink remove file and remove from local cache entry
 // SPECIFIC
 func (fs *BaseFS) Unlink(ctx context.Context, op *fuseops.UnlinkOp) (err error) {
-	if fs.Config.Safemode && op.Parent == fuseops.RootInodeID {
+	/*if fs.Config.Options.Readonly {
 		return syscall.EPERM
 	}
+
+	/*if op.Parent == fuseops.RootInodeID {
+		return syscall.EPERM
+	}*/
 	parentEntry := fs.Root.FindByInode(op.Parent)
 	if parentEntry == nil {
 		return fuse.ENOENT
@@ -458,9 +473,13 @@ func (fs *BaseFS) Unlink(ctx context.Context, op *fuseops.UnlinkOp) (err error)
 
 // MkDir creates a directory on a parent dir
 func (fs *BaseFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) (err error) {
-	if fs.Config.Safemode && op.Parent == fuseops.RootInodeID {
+	/*if fs.Config.Options.Readonly {
 		return syscall.EPERM
-	}
+	}*/
+
+	/*if op.Parent == fuseops.RootInodeID {
+		return syscall.EPERM
+	}*/
 
 	parentFile := fs.Root.FindByInode(op.Parent)
 	if parentFile == nil {
@@ -484,9 +503,13 @@ func (fs *BaseFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) (err error) {
 
 // RmDir fuse implementation
 func (fs *BaseFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) (err error) {
-	if fs.Config.Safemode && op.Parent == fuseops.RootInodeID {
+	/*if fs.Config.Options.Readonly {
 		return syscall.EPERM
-	}
+	}*/
+
+	/*if op.Parent == fuseops.RootInodeID {
+		return syscall.EPERM
+	}*/
 
 	parentFile := fs.Root.FindByInode(op.Parent)
 	if parentFile == nil {
@@ -505,10 +528,13 @@ func (fs *BaseFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) (err error) {
 
 // Rename fuse implementation
 func (fs *BaseFS) Rename(ctx context.Context, op *fuseops.RenameOp) (err error) {
+	/*if fs.Config.Options.Readonly {
+		return syscall.EPERM
+	}*/
 
-	if fs.Config.Safemode && (op.OldParent == fuseops.RootInodeID || op.NewParent == fuseops.RootInodeID) {
+	/*if op.OldParent == fuseops.RootInodeID || op.NewParent == fuseops.RootInodeID {
 		return syscall.EPERM
-	}
+	}*/
 	oldParentEntry := fs.Root.FindByInode(op.OldParent)
 	if oldParentEntry == nil {
 		return fuse.ENOENT

+ 7 - 6
internal/fs/basefs/file_container.go

@@ -24,18 +24,19 @@ type FileContainer struct {
 }
 
 func NewFileContainer(fs *BaseFS) *FileContainer {
+
 	fc := &FileContainer{
 		FileEntries: map[fuseops.InodeID]*FileEntry{},
 		fs:          fs,
 		//client:  fs.Client,
 		inodeMU: &sync.Mutex{},
-		uid:     fs.Config.UID,
-		gid:     fs.Config.GID,
+		uid:     fs.Config.Options.UID,
+		gid:     fs.Config.Options.GID,
 	}
 	rootEntry := fc.FileEntry(nil, fuseops.RootInodeID)
 	rootEntry.Attr.Mode = os.FileMode(0755) | os.ModeDir
-	rootEntry.Attr.Uid = fs.Config.UID
-	rootEntry.Attr.Gid = fs.Config.GID
+	rootEntry.Attr.Uid = fc.uid
+	rootEntry.Attr.Gid = fc.gid
 
 	return fc
 }
@@ -169,7 +170,6 @@ func (fc *FileContainer) FileEntry(file *File, inodeOps ...fuseops.InodeID) *Fil
 		log.Println("Filename contains invalid chars, sanitizing: '%s'-'%s'", name, newName)
 		name = newName
 	}
-
 	fe := &FileEntry{
 		Inode: inode,
 		Name:  name,
@@ -177,6 +177,7 @@ func (fc *FileContainer) FileEntry(file *File, inodeOps ...fuseops.InodeID) *Fil
 	// Temp gfile?
 	if file != nil {
 		fe.SetFile(file, fc.uid, fc.gid)
+		//fe.SetFile(file)
 	}
 	fc.FileEntries[inode] = fe
 
@@ -209,8 +210,8 @@ func (fc *FileContainer) Sync(fe *FileEntry) (err error) {
 	if err != nil {
 		return err
 	}
-	log.Println("Uploaded file size:", upFile.Size)
 	fe.SetFile(upFile, fc.uid, fc.gid) // update local GFile entry
+	//fe.SetFile(upFile) // update local GFile entry
 	return
 
 }

+ 4 - 5
internal/fs/dropboxfs/dropboxfs.go

@@ -1,22 +1,21 @@
 package dropboxfs
 
 import (
-	"io/ioutil"
-	glog "log"
-
 	"dev.hexasoftware.com/hxs/cloudmount/internal/core"
 	"dev.hexasoftware.com/hxs/cloudmount/internal/fs/basefs"
 	"dev.hexasoftware.com/hxs/prettylog"
 )
 
 var (
-	log = glog.New(ioutil.Discard, "", 0)
+	pname  = "dropboxfs"
+	log    = prettylog.Dummy()
+	errlog = prettylog.New(pname + "-err")
 )
 
 // New Create basefs with Dropbox service
 func New(core *core.Core) core.DriverFS {
 	if core.Config.VerboseLog {
-		log = prettylog.New("dropboxfs")
+		log = prettylog.New(pname)
 	}
 	fs := basefs.New(core)
 	fs.Service = NewService(&core.Config) // DropBoxService

+ 4 - 3
internal/fs/dropboxfs/service.go

@@ -10,6 +10,7 @@ import (
 	"golang.org/x/oauth2"
 
 	"dev.hexasoftware.com/hxs/cloudmount/internal/core"
+	"dev.hexasoftware.com/hxs/cloudmount/internal/coreutil"
 	"dev.hexasoftware.com/hxs/cloudmount/internal/fs/basefs"
 	"dev.hexasoftware.com/hxs/cloudmount/internal/oauth2util"
 
@@ -29,9 +30,9 @@ func NewService(coreConfig *core.Config) *Service {
 	log.Println("Initializing dropbox service")
 	log.Println("Source config:", coreConfig.Source)
 
-	err := core.ParseConfig(coreConfig.Source, &serviceConfig)
+	err := coreutil.ParseConfig(coreConfig.Source, &serviceConfig)
 	if err != nil {
-		log.Fatalf("Unable to read <source>: %v", err)
+		errlog.Fatalf("Unable to read <source>: %v", err)
 	}
 	config := &oauth2.Config{
 		ClientID:     serviceConfig.ClientSecret.ClientID,
@@ -46,7 +47,7 @@ func NewService(coreConfig *core.Config) *Service {
 	if serviceConfig.Auth == nil {
 		tok := oauth2util.GetTokenFromWeb(config)
 		serviceConfig.Auth = tok
-		core.SaveConfig(coreConfig.Source, &serviceConfig)
+		coreutil.SaveConfig(coreConfig.Source, &serviceConfig)
 	}
 
 	dbconfig := dropbox.Config{Token: serviceConfig.Auth.AccessToken}

+ 7 - 1
internal/fs/gdrivefs/gdrivefs.go

@@ -7,12 +7,18 @@ import (
 )
 
 var (
-	log = prettylog.New("gdrivefs")
+	pname  = "gdrive"
+	log    = prettylog.Dummy()
+	errlog = prettylog.New(pname + "-err")
 )
 
 // New new Filesystem implementation based on gdrive Service
 func New(core *core.Core) core.DriverFS {
 
+	if core.Config.VerboseLog {
+		log = prettylog.New(pname)
+	}
+
 	fs := basefs.New(core)
 	fs.Service = NewService(&core.Config)
 

+ 5 - 4
internal/fs/gdrivefs/service.go

@@ -9,6 +9,7 @@ import (
 	"golang.org/x/oauth2"
 
 	"dev.hexasoftware.com/hxs/cloudmount/internal/core"
+	"dev.hexasoftware.com/hxs/cloudmount/internal/coreutil"
 	"dev.hexasoftware.com/hxs/cloudmount/internal/fs/basefs"
 	"dev.hexasoftware.com/hxs/cloudmount/internal/oauth2util"
 
@@ -32,9 +33,9 @@ func NewService(coreConfig *core.Config) *Service {
 	log.Println("Initializing gdrive service")
 	log.Println("Source config:", coreConfig.Source)
 
-	err := core.ParseConfig(coreConfig.Source, &serviceConfig)
+	err := coreutil.ParseConfig(coreConfig.Source, &serviceConfig)
 	if err != nil {
-		log.Fatalf("Unable to read <source>: %v", err)
+		errlog.Fatalf("Unable to read <source>: %v", err)
 	}
 	config := &oauth2.Config{
 		ClientID:     serviceConfig.ClientSecret.ClientID,
@@ -49,13 +50,13 @@ func NewService(coreConfig *core.Config) *Service {
 	if serviceConfig.Auth == nil {
 		tok := oauth2util.GetTokenFromWeb(config)
 		serviceConfig.Auth = tok
-		core.SaveConfig(coreConfig.Source, &serviceConfig)
+		coreutil.SaveConfig(coreConfig.Source, &serviceConfig)
 	}
 
 	client := config.Client(oauth2.NoContext, serviceConfig.Auth)
 	driveCli, err := drive.New(client)
 	if err != nil {
-		log.Fatalf("Unable to retrieve drive Client: %v", err)
+		errlog.Fatalf("Unable to retrieve drive Client: %v", err)
 	}
 
 	return &Service{client: driveCli}

+ 2 - 3
main.go

@@ -7,7 +7,6 @@ package main
 
 import (
 	"fmt"
-	"net/http"
 	"os"
 
 	"os/exec"
@@ -25,14 +24,14 @@ var (
 
 func main() {
 	// TODO: TEMP
-	{
+	/*{
 		// Globally insecure SSL for debugging
 		r, _ := http.NewRequest("GET", "http://localhost", nil)
 		cli := &http.Client{}
 		cli.Do(r)
 		tr := http.DefaultTransport.(*http.Transport)
 		tr.TLSClientConfig.InsecureSkipVerify = true
-	}
+	}*/
 
 	prettylog.Global()
 

+ 1 - 1
vendor/github.com/jacobsa/fuse/mount_config.go

@@ -165,7 +165,7 @@ func (c *MountConfig) toMap() (opts map[string]string) {
 	// Cf. https://bugs.freedesktop.org/show_bug.cgi?id=90907
 	fsname := c.FSName
 	if runtime.GOOS == "linux" && fsname == "" {
-		fsname = "some_fuse_file_system"
+		fsname = "cloudmount"
 	}
 
 	// Special file system name?

+ 1 - 1
version.go

@@ -2,5 +2,5 @@ package main
 
 const (
   //Version contains version of the package
-  Version = "0.4-4-g806e41c - built: 2017-07-15 21:01:58 UTC"
+  Version = "0.4-5-gf01e8fb - built: 2017-07-17 05:09:51 UTC"
 )