Procházet zdrojové kódy

Improved refreshing, maintaining Inodes

Added signals and daemonize flag to run in background
luis před 7 roky
rodič
revize
2051cca55f

+ 37 - 0
README.md

@@ -0,0 +1,37 @@
+GDriveMount
+================
+07-05-2017
+
+Mount a google drive in a folder
+
+Usage:
+```bash
+gdrivemount [-d] [-v] destination_folder
+```
+
+Setup Google client secrets:
+
+[https://console.developers.google.com/apis/credentials](https://console.developers.google.com/apis/credentials)
+
+As of Google drive guidance:
+
+>	Turn on the Drive API
+
+>	1. Use [this wizard](https://console.developers.google.com/start/api?id=drive) to create or select a project in the Google Developers Console and automatically turn on the API. Click Continue, then Go to credentials.
+>	2. On the Add credentials to your project page, click the Cancel button.
+>	3. At the top of the page, select the OAuth consent screen tab. Select an Email address, enter a Product name if not already set, and click the Save button.
+>	4. Select the Credentials tab, click the Create credentials button and select OAuth client ID.
+>	5. Select the application type Other, enter the name "Drive API Quickstart", and click the Create button.
+>	6. Click OK to dismiss the resulting dialog.
+>	7. Click the file_download (Download JSON) button to the right of the client ID.
+
+Copy the downloaded JSON file to home directory as: 
+$HOME/.gdrivemount/client_secret.json
+
+
+
+
+TODO:
+--------
+Improve caching to refresh and save inodes
+

+ 8 - 1
src/gdrivemount/gdrive-cli.go

@@ -46,7 +46,14 @@ func tokenCacheFile() (string, error) {
 func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
 	authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
 
-	fmt.Printf("Go to the following link in your browser: %v\ntype the authorization code: ", authURL)
+	fmt.Printf(
+		`Go to the following link in your browser: 
+----------------------------------------------------------------------------------------------
+	%v
+----------------------------------------------------------------------------------------------
+
+type the authorization code: `, authURL)
+
 	var code string
 	if _, err := fmt.Scan(&code); err != nil {
 		log.Fatalf("Unable to read authorization code %v", err)

+ 77 - 14
src/gdrivemount/cmd/gdrivemount/main.go

@@ -3,14 +3,19 @@ package main
 import (
 	"context"
 	"flag"
+	"fmt"
 	"gdrivemount"
+	"os"
+	"os/exec"
+	"os/signal"
+	"runtime"
+	"syscall"
 
 	"github.com/jacobsa/fuse"
 	"github.com/jacobsa/fuse/fuseutil"
 
 	"dev.hexasoftware.com/hxs/prettylog"
-
-	_ "github.com/icattlecoder/godaemon" // No reason
+	//_ "github.com/icattlecoder/godaemon" // No reason
 )
 
 var (
@@ -18,34 +23,92 @@ var (
 )
 
 func main() {
+	var daemonize bool
+	var verboselog bool
 	prettylog.Global()
 	// getClient
-	gdriveFS := gdrivemount.NewGDriveFS()
+
+	flag.BoolVar(&daemonize, "d", false, "run app in background")
+	flag.BoolVar(&verboselog, "v", false, "Verbose log")
 
 	flag.Parse()
 	if len(flag.Args()) < 1 {
 		log.Fatal("Usage:\n gdrivemount MOUNTPOINT")
 	}
 
-	ctx := context.Background()
+	// Daemon
+	if daemonize {
+		subArgs := []string{}
+		for _, arg := range os.Args[1:] {
+			if arg == "-d" { // ignore daemon flag
+				continue
+			}
+			subArgs = append(subArgs, arg)
+		}
+
+		cmd := exec.Command(os.Args[0], subArgs...)
+		cmd.Start()
+		fmt.Println("[PID]", cmd.Process.Pid)
+		os.Exit(0)
+		return
+	}
+
+	gdriveFS := gdrivemount.NewGDriveFS()
 
+	//////////////
+	// Server
+	/////////
+	ctx := context.Background()
 	server := fuseutil.NewFileSystemServer(gdriveFS)
+	mountPath := flag.Arg(0)
+
+	var err error
+	var mfs *fuse.MountedFileSystem
 
-	//mfs, err := fuse.Mount(flag.Arg(0), server, &fuse.MountConfig{DebugLogger: prettylog.New("fuse"), ErrorLogger: prettylog.New("fuse-err")})
-	mfs, err := fuse.Mount(flag.Arg(0), server, &fuse.MountConfig{})
+	if 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{})
+	}
 	if err != nil {
 		log.Fatal("Failed mounting path", flag.Arg(0))
 	}
+
+	// Signal handling to refresh GDrive
+	sigs := make(chan os.Signal, 2)
+	signal.Notify(sigs, syscall.SIGUSR1, syscall.SIGHUP, syscall.SIGINT, os.Interrupt, syscall.SIGTERM)
+	go func() {
+		for sig := range sigs {
+			log.Println("Signal:", sig)
+			switch sig {
+			case syscall.SIGUSR1:
+				log.Println("Manually Refresh drive")
+				go gdriveFS.Refresh()
+			case syscall.SIGHUP:
+				log.Println("GC")
+				mem := runtime.MemStats{}
+				runtime.ReadMemStats(&mem)
+				log.Printf("Mem: %.2fMB", float64(mem.Alloc)/1024/1024)
+				runtime.GC()
+
+				runtime.ReadMemStats(&mem)
+				log.Printf("After gc: Mem: %.2fMB", float64(mem.Alloc)/1024/1024)
+
+			case os.Interrupt:
+				log.Println("Graceful unmount")
+				fuse.Unmount(mountPath)
+				os.Exit(1)
+			case syscall.SIGTERM:
+				log.Println("Graceful unmount")
+				fuse.Unmount(mountPath)
+				os.Exit(1)
+			}
+
+		}
+	}()
+
 	if err := mfs.Join(ctx); err != nil {
 		log.Fatalf("Joining: %v", err)
 	}
 
-	/* OLD
-	nfs := pathfs.NewPathNodeFs(gdriveFS, nil)
-	server, _, err := nodefs.MountRoot(flag.Arg(0), nfs.Root(), nil)
-	if err != nil {
-		log.Fatalf("Mount fail: %v\n", err)
-	}
-
-	server.Serve()*/
 }

+ 124 - 64
src/gdrivemount/fileentry.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
+	_ "log"
 	"net/http"
 	"os"
 	"strings"
@@ -15,50 +16,86 @@ import (
 
 //FileEntry entry to handle files
 type FileEntry struct {
-	parent *FileEntry
-	fs     *GDriveFS
-	GFile  *drive.File
-	isDir  bool
-	Name   string // local name
+	//parent *FileEntry
+	fs    *GDriveFS   // GDrive FS
+	GFile *drive.File // GDrive file
+	isDir bool        // Is dir
+	Name  string      // local name
 	// fuseops
 	Inode fuseops.InodeID
-	Attr  fuseops.InodeAttributes
+	Attr  fuseops.InodeAttributes // Cached attributes
 
 	// cache file
-	tempFile *os.File
+	tempFile *os.File // Cached file
 	// childs
-	fileList []*FileEntry // children
+	children []*FileEntry // children
 }
 
-func (fe *FileEntry) removeEntry(entry *FileEntry) {
+func NewFileEntry(fs *GDriveFS) *FileEntry {
+	return &FileEntry{
+		fs:       fs,
+		children: []*FileEntry{},
+		Attr:     fuseops.InodeAttributes{},
+	}
+}
+
+func (fe *FileEntry) AddChild(child *FileEntry) {
+	//child.parent = fe // is this needed at all?
+	// Solve name here?
+
+	fe.children = append(fe.children, child)
+}
+
+func (fe *FileEntry) RemoveChild(child *FileEntry) {
 	toremove := -1
-	for i, v := range fe.fileList {
-		if v == entry {
+	for i, v := range fe.children {
+		if v == child {
 			toremove = i
 			break
 		}
 	}
-
 	if toremove == -1 {
 		return
 	}
-	fe.fileList = append(fe.fileList[:toremove], fe.fileList[toremove+1:]...)
+	fe.children = append(fe.children[:toremove], fe.children[toremove+1:]...)
 }
 
-// useful for debug to count the entries
-func (fe *FileEntry) count() int {
+// useful for debug to count children
+func (fe *FileEntry) Count() int {
 	count := 0
 
-	for _, c := range fe.fileList {
-		count += c.count()
+	for _, c := range fe.children {
+		count += c.Count()
 	}
-	return count + len(fe.fileList)
+	return count + len(fe.children)
+}
 
+// SetGFile update attributes and set drive.File
+func (fe *FileEntry) SetGFile(f *drive.File) {
+	// Create Attribute
+	attr := fuseops.InodeAttributes{}
+	attr.Nlink = 1
+	attr.Size = uint64(f.Size)
+	// Temp
+	attr.Uid = fe.fs.getUID()
+	attr.Gid = fe.fs.getGID()
+	attr.Crtime, _ = time.Parse(time.RFC3339, f.CreatedTime)
+	attr.Ctime = attr.Crtime // Set CTime to created, although it is change inode metadata
+	attr.Mtime, _ = time.Parse(time.RFC3339, f.ModifiedTime)
+	attr.Atime = attr.Mtime // Set access time to modified, not sure if gdrive has access time
+
+	attr.Mode = os.FileMode(0644) // default
+
+	if f.MimeType == "application/vnd.google-apps.folder" {
+		attr.Mode = os.FileMode(0755) | os.ModeDir
+	}
+
+	fe.GFile = f
+	fe.Attr = attr
 }
 
-// Sync cached , upload
-// Clear cache too
-func (fe *FileEntry) sync() (err error) {
+// Sync cached , upload to gdrive
+func (fe *FileEntry) Sync() (err error) {
 	if fe.tempFile == nil {
 		return
 	}
@@ -66,24 +103,25 @@ func (fe *FileEntry) sync() (err error) {
 	fe.tempFile.Seek(0, io.SeekStart)
 
 	ngFile := &drive.File{}
-
 	up := fe.fs.srv.Files.Update(fe.GFile.Id, ngFile)
 	_, err = up.Media(fe.tempFile).Do()
-
 	return
 
 }
-func (fe *FileEntry) clearCache() (err error) {
+
+//ClearCache remove local file
+func (fe *FileEntry) ClearCache() (err error) {
 	if fe.tempFile == nil {
 		return
 	}
-	//fe.sync() // Sync?
 	fe.tempFile.Close()
 	os.Remove(fe.tempFile.Name())
 	fe.tempFile = nil
 	return
 }
-func (fe *FileEntry) cache() *os.File {
+
+// Cache download GDrive file to a temporary local file or return already created file
+func (fe *FileEntry) Cache() *os.File {
 	if fe.tempFile != nil {
 		return fe.tempFile
 	}
@@ -109,7 +147,7 @@ func (fe *FileEntry) cache() *os.File {
 	defer res.Body.Close()
 
 	// Local copy
-	fe.tempFile, err = ioutil.TempFile(os.TempDir(), "gdfs")
+	fe.tempFile, err = ioutil.TempFile(os.TempDir(), "gdfs") // TODO: const this elsewhere
 	if err != nil {
 		log.Println("Error creating temp file")
 		return nil
@@ -121,15 +159,38 @@ func (fe *FileEntry) cache() *os.File {
 
 }
 
+// Find the right parent?
+// WRONG
+func (fe *FileEntry) solveAppendGFile(f *drive.File, inode fuseops.InodeID) *FileEntry {
+
+	fil := fe.FindByGID(f.Id, true)
+	if fil != nil { // ignore existing ID
+		return fil
+	}
+
+	if len(f.Parents) == 0 {
+		return fe.AppendGFile(f, inode) // = append(fs.root.fileList, entry)
+	}
+	for _, parent := range f.Parents { // hierarchy add
+		parentEntry := fe.FindByGID(parent, true)
+		if parentEntry == nil {
+			log.Fatalln("Non existent parent", parent)
+		}
+		// Here
+		return parentEntry.AppendGFile(f, inode)
+	}
+	return nil
+}
+
 // Load append whatever?
 // append file to this tree
-func (fe *FileEntry) appendGFile(f *drive.File) *FileEntry {
+func (fe *FileEntry) AppendGFile(f *drive.File, inode fuseops.InodeID) *FileEntry {
 
 	name := f.Name
 	count := 1
 	nameParts := strings.Split(f.Name, ".")
 	for {
-		en := fe.findByName(name, false) // locally only
+		en := fe.FindByName(name, false) // locally only
 		if en == nil {                   // ok we want no value
 			break
 		}
@@ -141,50 +202,35 @@ func (fe *FileEntry) appendGFile(f *drive.File) *FileEntry {
 		}
 	}
 
-	// Create Attribute
-	attr := fuseops.InodeAttributes{}
-	attr.Nlink = 1
-	attr.Size = uint64(f.Size)
-	// Temp
-	attr.Uid = fe.fs.getUID()
-	attr.Gid = fe.fs.getGID()
-	attr.Crtime, _ = time.Parse(time.RFC3339, f.CreatedTime)
-	attr.Mtime, _ = time.Parse(time.RFC3339, f.ModifiedTime)
-	attr.Mode = os.FileMode(0644) // default
-
-	if f.MimeType == "application/vnd.google-apps.folder" {
-		attr.Mode = os.FileMode(0755) | os.ModeDir
-	}
 	// Create an entry
 
+	//log.Println("Creating new file entry for name:", name, "for GFile:", f.Name)
 	// lock from find inode to fileList append
-	entry := &FileEntry{
-		parent: fe,
-		fs:     fe.fs,
-		GFile:  f,
-		Name:   name,                    // we dont need name
-		Inode:  fe.fs.findUnusedInode(), // Lock somehow
-		Attr:   attr,
-		//fileMap: map[string]*FileEntry{},
-		fileList: []*FileEntry{},
-	}
-
-	fe.fileList = append(fe.fileList, entry)
+	entry := NewFileEntry(fe.fs)
+	entry.Name = name
+	entry.SetGFile(f)
+	entry.Inode = inode
+
+	fe.AddChild(entry)
+
+	//fe.fileList = append(fe.fileList, entry)
 	//fe.fileMap[f.Name] = entry
 
 	return entry
 }
-func (fe *FileEntry) findByInode(inode fuseops.InodeID, recurse bool) *FileEntry {
+
+//FindByInode find by Inode or return self
+func (fe *FileEntry) FindByInode(inode fuseops.InodeID, recurse bool) *FileEntry {
 	if inode == fe.Inode {
 		return fe // return self
 	}
 	// Recurse??
-	for _, e := range fe.fileList {
+	for _, e := range fe.children {
 		if e.Inode == inode {
 			return e
 		}
 		if recurse {
-			re := e.findByInode(inode, recurse)
+			re := e.FindByInode(inode, recurse)
 			if re != nil {
 				return re
 			}
@@ -194,14 +240,15 @@ func (fe *FileEntry) findByInode(inode fuseops.InodeID, recurse bool) *FileEntry
 	return nil
 }
 
-func (fe *FileEntry) findByName(name string, recurse bool) *FileEntry {
+// FindByName return a child entry by name
+func (fe *FileEntry) FindByName(name string, recurse bool) *FileEntry {
 	// Recurse??
-	for _, e := range fe.fileList {
+	for _, e := range fe.children {
 		if e.Name == name {
 			return e
 		}
 		if recurse {
-			re := e.findByName(name, recurse)
+			re := e.FindByName(name, recurse)
 			if re != nil {
 				return re
 			}
@@ -211,14 +258,15 @@ func (fe *FileEntry) findByName(name string, recurse bool) *FileEntry {
 	return nil
 }
 
-func (fe *FileEntry) findByGID(gdriveID string, recurse bool) *FileEntry {
+// FindByGID find by google drive ID
+func (fe *FileEntry) FindByGID(gdriveID string, recurse bool) *FileEntry {
 	// Recurse??
-	for _, e := range fe.fileList {
+	for _, e := range fe.children {
 		if e.GFile.Id == gdriveID {
 			return e
 		}
 		if recurse {
-			re := e.findByGID(gdriveID, recurse)
+			re := e.FindByGID(gdriveID, recurse)
 			if re != nil {
 				return re
 			}
@@ -227,3 +275,15 @@ func (fe *FileEntry) findByGID(gdriveID string, recurse bool) *FileEntry {
 	// For each child we findByInode
 	return nil
 }
+
+func (fe *FileEntry) FindUnusedInode() fuseops.InodeID {
+	var inode fuseops.InodeID
+	for inode = 2; inode < 99999; inode++ {
+		f := fe.FindByInode(inode, true)
+		if f == nil {
+			return inode
+		}
+	}
+	log.Println("0 Inode ODD")
+	return 0
+}

+ 141 - 189
src/gdrivemount/gdrive-fuse.go

@@ -26,9 +26,8 @@ var (
 )
 
 type fileHandle struct {
-	handleID fuseops.HandleID
-	entry    *FileEntry
-	//tempFile     *os.File
+	handleID     fuseops.HandleID
+	entry        *FileEntry
 	uploadOnDone bool
 	// Testing
 	entries []fuseutil.Dirent
@@ -41,65 +40,24 @@ type fileHandle struct {
 
 // GDriveFS handler
 type GDriveFS struct {
-	fuseutil.NotImplementedFileSystem
-	srv *drive.Service
+	fuseutil.NotImplementedFileSystem // Defaults
+	srv                               *drive.Service
 
 	osuser *user.User
 	root   *FileEntry // hiearchy reference
 
 	fileHandles map[fuseops.HandleID]*fileHandle
+	nextRefresh time.Time
+
+	//fileMap map[string]
+	// Map IDS with FileEntries
 }
 
 ////////////////////////////////////////////////////////
 // TOOLS & HELPERS
 ////////////////////////////////////////////////////////
 
-// appendFile solve parent before add,
-func (fs *GDriveFS) appendFile(f *drive.File) *FileEntry {
-
-	fil := fs.root.findByGID(f.Id, true)
-	if fil != nil { // ignore existing ID
-		return nil
-	}
-
-	var entry *FileEntry
-	if len(f.Parents) == 0 {
-		entry = fs.root.appendGFile(f) // = append(fs.root.fileList, entry)
-	}
-	if len(f.Parents) > 1 {
-		log.Println("This one has more than 1 parent:", f.Parents)
-	}
-	for _, parent := range f.Parents { // hierarchy add
-		parentEntry := fs.root.findByGID(parent, true)
-		if parentEntry == nil {
-			log.Fatalln("Non existent parent", parent)
-		}
-
-		// Here
-		entry = parentEntry.appendGFile(f)
-	}
-	return entry
-}
-
-func (fs *GDriveFS) defaultAttributes() fuseops.InodeAttributes {
-	uid, err := strconv.Atoi(fs.osuser.Uid)
-	if err != nil {
-		panic("Cannot convert user to int?")
-	}
-	gid, err := strconv.Atoi(fs.osuser.Gid)
-	if err != nil {
-		panic("Cannot convert gid to int?")
-	}
-
-	return fuseops.InodeAttributes{
-		Nlink: 1,
-		Mode:  0644, // default regular file
-		Uid:   uint32(uid),
-		Gid:   uint32(gid),
-	}
-}
-
-func (fs *GDriveFS) findUnusedHandle() *fileHandle {
+func (fs *GDriveFS) createHandle() *fileHandle {
 	// Lock here instead
 
 	var handle fuseops.HandleID
@@ -110,34 +68,20 @@ func (fs *GDriveFS) findUnusedHandle() *fileHandle {
 			break
 		}
 	}
+
 	fh := &fileHandle{handleID: handle}
 	fs.fileHandles[handle] = fh
 
 	return fh
 }
 
-func (fs *GDriveFS) findUnusedInode() fuseops.InodeID {
-	var inode fuseops.InodeID
-	for inode = 2; inode < 99999; inode++ {
-		f := fs.root.findByInode(inode, true)
-		if f == nil {
-			return inode
-		}
-	}
-	if inode == 4 {
-		log.Println("Inode is 4")
-
-	}
-	log.Println("0 Inode ODD")
-	return 0
-}
-
 func NewGDriveFS() *GDriveFS {
 
 	osuser, err := user.Current()
 	if err != nil {
 		log.Fatalf("Unable to fetch current user:", err)
 	}
+
 	fs := &GDriveFS{}
 	fs.osuser = osuser
 	fs.srv = GetDriveService()
@@ -154,20 +98,21 @@ func NewGDriveFS() *GDriveFS {
 		Inode: fuseops.RootInodeID,
 		Name:  "",
 		//fileMap: map[string]*FileEntry{},
-		fileList: []*FileEntry{},
+		children: []*FileEntry{},
 		isDir:    true,
 	}
 	fs.fileHandles = map[fuseops.HandleID]*fileHandle{}
 
-	entry := fs.root.appendGFile(&drive.File{Id: "0", Name: "Loading..."})
+	// Temporary entry
+	entry := fs.root.AppendGFile(&drive.File{Id: "0", Name: "Loading..."}, 999999)
 	entry.Attr.Mode = os.FileMode(0)
 
-	go fs.refresh() // async fetch
+	fs.timedRefresh()
 
 	return fs
 }
 
-// Cache somewhere
+// Cache somewhere?
 func (fs *GDriveFS) getUID() uint32 {
 	uid, _ := strconv.Atoi(fs.osuser.Uid)
 	return uint32(uid)
@@ -177,49 +122,87 @@ func (fs *GDriveFS) getGID() uint32 {
 	return uint32(gid)
 }
 
+func (fs *GDriveFS) timedRefresh() {
+
+	go func() {
+		for {
+			if time.Now().After(fs.nextRefresh) {
+				fs.Refresh()
+			}
+			time.Sleep(2 * time.Minute) // 2 minutes
+		}
+	}()
+
+}
+
 // Reload service files
-func (fs *GDriveFS) refresh() {
-	fileMap := map[string]*drive.File{} // Temporary map by google drive ID
+func (fs *GDriveFS) Refresh() {
+	fs.nextRefresh = time.Now().Add(1 * time.Minute)
+
+	fileList := []*drive.File{}
+	fileMap := map[string]*drive.File{} // Temporary map by google drive fileID
+	//fileMap := map[string]*FileEntry{}
 
 	gdFields := googleapi.Field("nextPageToken, files(id,name,size,mimeType,parents,createdTime,modifiedTime)")
 	log.Println("Loading file entries from gdrive")
-	r, err := fs.srv.Files.List().PageSize(1000).
+	r, err := fs.srv.Files.List().
+		OrderBy("createdTime").
+		PageSize(1000).
 		SupportsTeamDrives(true).
 		IncludeTeamDriveItems(true).
 		Fields(gdFields).
 		Do()
 	if err != nil {
-		panic(err)
-	}
-	log.Println("Loaded:", len(r.Files))
-
-	for _, f := range r.Files {
-		fileMap[f.Id] = f
+		log.Println("GDrive ERR:", err)
+		return
 	}
+	fileList = append(fileList, r.Files...)
 
-	// Rest of the page
+	// Rest of the pages
 	for r.NextPageToken != "" {
-		log.Println("Loading next page")
-		r, err = fs.srv.Files.List().PageToken(r.NextPageToken).Do()
+		r, err = fs.srv.Files.List().
+			OrderBy("createdTime").
+			PageToken(r.NextPageToken).
+			Fields(gdFields).
+			Do()
 		if err != nil {
-			panic(err)
+			log.Println("GDrive ERR:", err)
+			return
 		}
-		for _, f := range r.Files {
-			fileMap[f.Id] = f
+		fileList = append(fileList, r.Files...)
+	}
+	log.Println("Total entries:", len(fileList))
+
+	// TimeSort
+	/*log.Println("Sort by time")
+	sort.Slice(fileList, func(i, j int) bool {
+		createdTimeI, _ := time.Parse(time.RFC3339, fileList[i].CreatedTime)
+		createdTimeJ, _ := time.Parse(time.RFC3339, fileList[i].CreatedTime)
+		if createdTimeI.Before(createdTimeJ) {
+			return true
 		}
+		return false
+	})*/
+
+	// Cache ID for faster retrieval, might not be necessary
+	for _, f := range fileList {
+		fileMap[f.Id] = f
 	}
-	log.Println("Total entries:", len(fileMap))
 
 	if err != nil || r == nil {
-		log.Fatal("Unable to retrieve files", err)
+		log.Println("Unable to retrieve files", err)
+		return
 	}
 
-	fs.root.fileList = []*FileEntry{} // clear fileList
+	// Create clean fileList
+	root := NewFileEntry(fs)
+
 	// Helper func to recurse
 	// Everything loaded we add to our entries
-	var appendParentOf func(f *drive.File)
-	appendParentOf = func(f *drive.File) {
-		for _, pID := range f.Parents {
+	// Add file and its parents priorizing it parent
+	var appendFile func(df *drive.File)
+	appendFile = func(df *drive.File) {
+		for _, pID := range df.Parents {
 			parentFile, ok := fileMap[pID]
 			if !ok {
 				parentFile, err = fs.srv.Files.Get(pID).Do()
@@ -228,29 +211,44 @@ func (fs *GDriveFS) refresh() {
 				}
 				fileMap[parentFile.Id] = parentFile
 			}
-			appendParentOf(parentFile) // Recurse
-			fs.appendFile(parentFile)
+			appendFile(parentFile) // Recurse
+		}
+		// Find existing entry
+		var inode fuseops.InodeID
+		entry := fs.root.FindByGID(df.Id, true)
+		if entry == nil {
+			inode = root.FindUnusedInode()
+		} else {
+			inode = entry.Inode
 		}
+
+		newEntry := root.solveAppendGFile(df, inode)     // Find right parent
+		if entry != nil && entry.GFile.Name == df.Name { // Copy name from old entry
+			newEntry.Name = entry.Name
+		}
+
+		// add File
 	}
 
-	for _, f := range fileMap {
-		appendParentOf(f) // Check parent first
-		fs.appendFile(f)
+	for _, f := range fileList { // Ordered
+		appendFile(f) // Check parent first
 	}
-	log.Println("Refresh done")
 
-	log.Println("File count:", fs.root.count())
+	log.Println("Refresh done, update root")
+	fs.root.children = root.children
+
+	log.Println("File count:", fs.root.Count())
 }
 
 // OpenDir return nil error allows open dir
 func (fs *GDriveFS) OpenDir(ctx context.Context, op *fuseops.OpenDirOp) (err error) {
 
-	entry := fs.root.findByInode(op.Inode, true)
+	entry := fs.root.FindByInode(op.Inode, true)
 	if entry == nil {
 		return fuse.ENOENT
 	}
 
-	fh := fs.findUnusedHandle()
+	fh := fs.createHandle()
 	fh.entry = entry
 	op.Handle = fh.handleID
 
@@ -267,10 +265,7 @@ func (fs *GDriveFS) ReadDir(ctx context.Context, op *fuseops.ReadDirOp) (err err
 	if op.Offset == 0 { // Rebuild/rewind dir list
 		fh.entries = []fuseutil.Dirent{}
 
-		//fh.buf = make([]byte, 1000000) // Temp bigbuf somehow
-		//written := 0
-
-		for i, v := range fh.entry.fileList {
+		for i, v := range fh.entry.children {
 			fusetype := fuseutil.DT_File
 			if v.isDir {
 				fusetype = fuseutil.DT_Directory
@@ -286,20 +281,6 @@ func (fs *GDriveFS) ReadDir(ctx context.Context, op *fuseops.ReadDirOp) (err err
 		}
 	}
 
-	// local Buftest
-
-	// Raw copy
-	/*log.Println("Just copy data off:", op.Offset)
-	for {
-		n := copy(op.Dst[op.BytesRead:], fh.buf[op.Offset:])
-		if n == 0 {
-
-			break
-		}
-		log.Println("Written:", n)
-		op.BytesRead += n
-	}*/
-
 	index := int(op.Offset)
 	if index > len(fh.entries) {
 		return fuse.EINVAL
@@ -307,7 +288,6 @@ func (fs *GDriveFS) ReadDir(ctx context.Context, op *fuseops.ReadDirOp) (err err
 	if index > 0 {
 		index++
 	}
-	count := 0
 	for i := index; i < len(fh.entries); i++ {
 		n := fuseutil.WriteDirent(op.Dst[op.BytesRead:], fh.entries[i])
 		//log.Println("Written:", n)
@@ -315,41 +295,7 @@ func (fs *GDriveFS) ReadDir(ctx context.Context, op *fuseops.ReadDirOp) (err err
 			break
 		}
 		op.BytesRead += n
-		count++
 	}
-	//log.Printf("Written %d Dirent: '%s' TotalSent: %d", count, fh.entry.Name, op.BytesRead)
-
-	/*log.Println("Sending from offset:", op.Offset)
-	entries = entries[op.Offset:]
-
-	log.Println("Total entries for this tree:", len(dir.entry.fileList))
-
-	count := 0
-	offCount := int(op.Offset)
-	// Resume at the specified offset into the array.
-	for i, v := range entries {
-		fusetype := fuseutil.DT_File
-		if v.isDir {
-			fusetype = fuseutil.DT_Directory
-		}
-		dirEnt := fuseutil.Dirent{
-			Inode:  v.Inode,
-			Name:   v.Name,
-			Type:   fusetype,
-			Offset: fuseops.DirOffset(op.Offset + fuseops.DirOffset(i+1)),
-		}
-		//log.Println("Entry offset:", dirEnt.Offset)
-		n := fuseutil.WriteDirent(op.Dst[op.BytesRead:], dirEnt)
-		if n == 0 { // let go
-			log.Println("Broke the Write")
-			break
-		}
-
-		count++
-		offCount++
-		op.BytesRead += n
-	}
-	log.Println("BytesRead:", op.BytesRead, " count:", count, " offCount:", offCount, " last:", len(dir.entry.fileList)-count)*/
 	return
 }
 
@@ -361,7 +307,7 @@ func (fs *GDriveFS) SetInodeAttributes(ctx context.Context, op *fuseops.SetInode
 //GetInodeAttributes return attributes
 func (fs *GDriveFS) GetInodeAttributes(ctx context.Context, op *fuseops.GetInodeAttributesOp) (err error) {
 
-	f := fs.root.findByInode(op.Inode, true)
+	f := fs.root.FindByInode(op.Inode, true)
 	if f == nil {
 		return fuse.ENOENT
 	}
@@ -380,14 +326,14 @@ func (fs *GDriveFS) ReleaseDirHandle(ctx context.Context, op *fuseops.ReleaseDir
 // LookUpInode based on Parent and Name we return a self cached inode
 func (fs *GDriveFS) LookUpInode(ctx context.Context, op *fuseops.LookUpInodeOp) (err error) {
 
-	parentFile := fs.root.findByInode(op.Parent, true) // true means transverse all
+	parentFile := fs.root.FindByInode(op.Parent, true) // true means transverse all
 	if parentFile == nil {
 		return fuse.ENOENT
 	}
 
 	now := time.Now()
 	// Transverse only local
-	f := parentFile.findByName(op.Name, false)
+	f := parentFile.FindByName(op.Name, false)
 	if f == nil {
 		return fuse.ENOENT
 	}
@@ -395,8 +341,8 @@ func (fs *GDriveFS) LookUpInode(ctx context.Context, op *fuseops.LookUpInodeOp)
 	op.Entry = fuseops.ChildInodeEntry{
 		Attributes:           f.Attr,
 		Child:                f.Inode,
-		AttributesExpiration: now.Add(time.Minute),
-		EntryExpiration:      now.Add(time.Minute),
+		AttributesExpiration: now.Add(time.Second),
+		EntryExpiration:      now.Add(time.Second),
 	}
 	return
 }
@@ -422,10 +368,10 @@ func (fs *GDriveFS) GetXAttr(ctx context.Context, op *fuseops.GetXattrOp) (err e
 
 // OpenFile creates a temporary handle to be handled on read or write
 func (fs *GDriveFS) OpenFile(ctx context.Context, op *fuseops.OpenFileOp) (err error) {
-	f := fs.root.findByInode(op.Inode, true) // might not exists
+	f := fs.root.FindByInode(op.Inode, true) // might not exists
 
 	// Generate new handle
-	fh := fs.findUnusedHandle()
+	fh := fs.createHandle()
 	fh.entry = f
 
 	op.Handle = fh.handleID
@@ -438,11 +384,8 @@ func (fs *GDriveFS) OpenFile(ctx context.Context, op *fuseops.OpenFileOp) (err e
 func (fs *GDriveFS) ReadFile(ctx context.Context, op *fuseops.ReadFileOp) (err error) {
 	lf := fs.fileHandles[op.Handle]
 
-	localFile := lf.entry.cache()
+	localFile := lf.entry.Cache()
 	op.BytesRead, err = localFile.ReadAt(op.Dst, op.Offset)
-	if err != nil {
-		log.Println("Err reading file", err)
-	}
 	if err == io.EOF { // fuse does not expect a EOF
 		err = nil
 	}
@@ -453,16 +396,20 @@ func (fs *GDriveFS) ReadFile(ctx context.Context, op *fuseops.ReadFileOp) (err e
 // CreateFile creates empty file in google Drive and returns its ID and attributes, only allows file creation on 'My Drive'
 func (fs *GDriveFS) CreateFile(ctx context.Context, op *fuseops.CreateFileOp) (err error) {
 
-	parentFile := fs.root.findByInode(op.Parent, true)
+	parentFile := fs.root.FindByInode(op.Parent, true)
 	if parentFile == nil {
-		err = fuse.ENOENT
-		return
+		return fuse.ENOENT
 	}
 	// Only write on child folders
 	if parentFile.Inode == fuseops.RootInodeID {
 		return syscall.EPERM
 	}
 
+	existsFile := parentFile.FindByName(op.Name, false)
+	if existsFile != nil {
+		return fuse.EEXIST
+	}
+
 	// Generate ID
 	//genId, err := fs.srv.Files.GenerateIds().Count(1).Do()
 	//id := genId.Ids[0]
@@ -477,21 +424,20 @@ func (fs *GDriveFS) CreateFile(ctx context.Context, op *fuseops.CreateFileOp) (e
 		return
 	}
 
-	entry := parentFile.appendGFile(createdFile) // Add new created file
+	entry := parentFile.AppendGFile(createdFile, fs.root.FindUnusedInode()) // Add new created file
 	if entry == nil {
 		err = fuse.EINVAL
 		return
 	}
-	log.Println("File Created", entry)
 
-	localFile := entry.cache()
+	localFile := entry.Cache()
 	if localFile == nil {
 		return fuse.EINVAL
 	}
 	// Associate a temp file to a new handle
 	// Local copy
 	// Lock
-	fh := fs.findUnusedHandle()
+	fh := fs.createHandle()
 	fh.entry = entry
 	fh.uploadOnDone = true
 	//
@@ -516,7 +462,7 @@ func (fs *GDriveFS) WriteFile(ctx context.Context, op *fuseops.WriteFileOp) (err
 		return
 	}
 
-	localFile := lf.entry.cache()
+	localFile := lf.entry.Cache()
 	if localFile == nil {
 		return fuse.EINVAL
 	}
@@ -536,21 +482,20 @@ func (fs *GDriveFS) ReleaseFileHandle(ctx context.Context, op *fuseops.ReleaseFi
 	lf := fs.fileHandles[op.Handle]
 
 	if lf.uploadOnDone {
-		err = lf.entry.sync()
+		err = lf.entry.Sync()
 		if err != nil {
 			return fuse.EINVAL
 		}
 	}
-	lf.entry.clearCache()
+	lf.entry.ClearCache()
 	delete(fs.fileHandles, op.Handle)
 
-	//go fs.refresh()
 	return
 }
 
 // Unlink remove file and remove from local cache entry
 func (fs *GDriveFS) Unlink(ctx context.Context, op *fuseops.UnlinkOp) (err error) {
-	parentEntry := fs.root.findByInode(op.Parent, true)
+	parentEntry := fs.root.FindByInode(op.Parent, true)
 	if parentEntry == nil {
 		return fuse.ENOENT
 	}
@@ -558,7 +503,7 @@ func (fs *GDriveFS) Unlink(ctx context.Context, op *fuseops.UnlinkOp) (err error
 		return syscall.EPERM
 	}
 
-	fileEntry := parentEntry.findByName(op.Name, false)
+	fileEntry := parentEntry.FindByName(op.Name, false)
 	if fileEntry == nil {
 		return fuse.ENOATTR
 	}
@@ -567,7 +512,7 @@ func (fs *GDriveFS) Unlink(ctx context.Context, op *fuseops.UnlinkOp) (err error
 		return fuse.EIO
 	}
 
-	parentEntry.removeEntry(fileEntry)
+	parentEntry.RemoveChild(fileEntry)
 
 	return
 }
@@ -580,7 +525,7 @@ func (fs *GDriveFS) FlushFile(ctx context.Context, op *fuseops.FlushFileOp) (err
 // MkDir creates a directory on a parent dir
 func (fs *GDriveFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) (err error) {
 
-	parentFile := fs.root.findByInode(op.Parent, true)
+	parentFile := fs.root.FindByInode(op.Parent, true)
 	if parentFile == nil {
 		return fuse.ENOENT
 	}
@@ -597,7 +542,7 @@ func (fs *GDriveFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) (err error)
 	if err != nil {
 		return fuse.ENOATTR
 	}
-	entry := parentFile.appendGFile(fi)
+	entry := parentFile.AppendGFile(fi, fs.root.FindUnusedInode())
 	if entry == nil {
 		return fuse.EINVAL
 	}
@@ -615,7 +560,7 @@ func (fs *GDriveFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) (err error)
 // RmDir fuse implementation
 func (fs *GDriveFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) (err error) {
 
-	parentFile := fs.root.findByInode(op.Parent, true)
+	parentFile := fs.root.FindByInode(op.Parent, true)
 	if parentFile == nil {
 		return fuse.ENOENT
 	}
@@ -623,14 +568,14 @@ func (fs *GDriveFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) (err error)
 		return syscall.EPERM
 	}
 
-	theFile := parentFile.findByName(op.Name, false)
+	theFile := parentFile.FindByName(op.Name, false)
 
 	err = fs.srv.Files.Delete(theFile.GFile.Id).Do()
 	if err != nil {
 		return fuse.ENOTEMPTY
 	}
 
-	parentFile.removeEntry(theFile)
+	parentFile.RemoveChild(theFile)
 
 	// Remove from entry somehow
 
@@ -639,11 +584,11 @@ func (fs *GDriveFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) (err error)
 
 // Rename fuse implementation
 func (fs *GDriveFS) Rename(ctx context.Context, op *fuseops.RenameOp) (err error) {
-	oldParentFile := fs.root.findByInode(op.OldParent, true)
+	oldParentFile := fs.root.FindByInode(op.OldParent, true)
 	if oldParentFile == nil {
 		return fuse.ENOENT
 	}
-	newParentFile := fs.root.findByInode(op.NewParent, true)
+	newParentFile := fs.root.FindByInode(op.NewParent, true)
 	if newParentFile == nil {
 		return fuse.ENOENT
 	}
@@ -652,7 +597,14 @@ func (fs *GDriveFS) Rename(ctx context.Context, op *fuseops.RenameOp) (err error
 		return syscall.EPERM
 	}
 
-	oldFile := oldParentFile.findByName(op.OldName, false)
+	oldFile := oldParentFile.FindByName(op.OldName, false)
+
+	// Although GDrive allows duplicate names, there is some issue with inode caching
+	// So we prevent a rename to a file with same name
+	existsFile := newParentFile.FindByName(op.NewName, false)
+	if existsFile != nil {
+		return fuse.EEXIST
+	}
 
 	ngFile := &drive.File{
 		Name: op.NewName,
@@ -665,8 +617,8 @@ func (fs *GDriveFS) Rename(ctx context.Context, op *fuseops.RenameOp) (err error
 	}
 	updatedFile, err := updateCall.Do()
 
-	oldParentFile.removeEntry(oldFile)
-	newParentFile.appendGFile(updatedFile)
+	oldParentFile.RemoveChild(oldFile)
+	newParentFile.AppendGFile(updatedFile, oldFile.Inode)
 
 	return