|
@@ -26,9 +26,8 @@ var (
|
|
)
|
|
)
|
|
|
|
|
|
type fileHandle struct {
|
|
type fileHandle struct {
|
|
- handleID fuseops.HandleID
|
|
|
|
- entry *FileEntry
|
|
|
|
- //tempFile *os.File
|
|
|
|
|
|
+ handleID fuseops.HandleID
|
|
|
|
+ entry *FileEntry
|
|
uploadOnDone bool
|
|
uploadOnDone bool
|
|
// Testing
|
|
// Testing
|
|
entries []fuseutil.Dirent
|
|
entries []fuseutil.Dirent
|
|
@@ -41,65 +40,24 @@ type fileHandle struct {
|
|
|
|
|
|
// GDriveFS handler
|
|
// GDriveFS handler
|
|
type GDriveFS struct {
|
|
type GDriveFS struct {
|
|
- fuseutil.NotImplementedFileSystem
|
|
|
|
- srv *drive.Service
|
|
|
|
|
|
+ fuseutil.NotImplementedFileSystem // Defaults
|
|
|
|
+ srv *drive.Service
|
|
|
|
|
|
osuser *user.User
|
|
osuser *user.User
|
|
root *FileEntry // hiearchy reference
|
|
root *FileEntry // hiearchy reference
|
|
|
|
|
|
fileHandles map[fuseops.HandleID]*fileHandle
|
|
fileHandles map[fuseops.HandleID]*fileHandle
|
|
|
|
+ nextRefresh time.Time
|
|
|
|
+
|
|
|
|
+ //fileMap map[string]
|
|
|
|
+ // Map IDS with FileEntries
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////
|
|
// TOOLS & HELPERS
|
|
// 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
|
|
// Lock here instead
|
|
|
|
|
|
var handle fuseops.HandleID
|
|
var handle fuseops.HandleID
|
|
@@ -110,34 +68,20 @@ func (fs *GDriveFS) findUnusedHandle() *fileHandle {
|
|
break
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
fh := &fileHandle{handleID: handle}
|
|
fh := &fileHandle{handleID: handle}
|
|
fs.fileHandles[handle] = fh
|
|
fs.fileHandles[handle] = fh
|
|
|
|
|
|
return 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 {
|
|
func NewGDriveFS() *GDriveFS {
|
|
|
|
|
|
osuser, err := user.Current()
|
|
osuser, err := user.Current()
|
|
if err != nil {
|
|
if err != nil {
|
|
log.Fatalf("Unable to fetch current user:", err)
|
|
log.Fatalf("Unable to fetch current user:", err)
|
|
}
|
|
}
|
|
|
|
+
|
|
fs := &GDriveFS{}
|
|
fs := &GDriveFS{}
|
|
fs.osuser = osuser
|
|
fs.osuser = osuser
|
|
fs.srv = GetDriveService()
|
|
fs.srv = GetDriveService()
|
|
@@ -154,20 +98,21 @@ func NewGDriveFS() *GDriveFS {
|
|
Inode: fuseops.RootInodeID,
|
|
Inode: fuseops.RootInodeID,
|
|
Name: "",
|
|
Name: "",
|
|
//fileMap: map[string]*FileEntry{},
|
|
//fileMap: map[string]*FileEntry{},
|
|
- fileList: []*FileEntry{},
|
|
|
|
|
|
+ children: []*FileEntry{},
|
|
isDir: true,
|
|
isDir: true,
|
|
}
|
|
}
|
|
fs.fileHandles = map[fuseops.HandleID]*fileHandle{}
|
|
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)
|
|
entry.Attr.Mode = os.FileMode(0)
|
|
|
|
|
|
- go fs.refresh() // async fetch
|
|
|
|
|
|
+ fs.timedRefresh()
|
|
|
|
|
|
return fs
|
|
return fs
|
|
}
|
|
}
|
|
|
|
|
|
-// Cache somewhere
|
|
|
|
|
|
+// Cache somewhere?
|
|
func (fs *GDriveFS) getUID() uint32 {
|
|
func (fs *GDriveFS) getUID() uint32 {
|
|
uid, _ := strconv.Atoi(fs.osuser.Uid)
|
|
uid, _ := strconv.Atoi(fs.osuser.Uid)
|
|
return uint32(uid)
|
|
return uint32(uid)
|
|
@@ -177,49 +122,87 @@ func (fs *GDriveFS) getGID() uint32 {
|
|
return uint32(gid)
|
|
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
|
|
// 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)")
|
|
gdFields := googleapi.Field("nextPageToken, files(id,name,size,mimeType,parents,createdTime,modifiedTime)")
|
|
log.Println("Loading file entries from gdrive")
|
|
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).
|
|
SupportsTeamDrives(true).
|
|
IncludeTeamDriveItems(true).
|
|
IncludeTeamDriveItems(true).
|
|
Fields(gdFields).
|
|
Fields(gdFields).
|
|
Do()
|
|
Do()
|
|
if err != nil {
|
|
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 != "" {
|
|
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 {
|
|
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 {
|
|
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
|
|
// Helper func to recurse
|
|
// Everything loaded we add to our entries
|
|
// 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]
|
|
parentFile, ok := fileMap[pID]
|
|
if !ok {
|
|
if !ok {
|
|
parentFile, err = fs.srv.Files.Get(pID).Do()
|
|
parentFile, err = fs.srv.Files.Get(pID).Do()
|
|
@@ -228,29 +211,44 @@ func (fs *GDriveFS) refresh() {
|
|
}
|
|
}
|
|
fileMap[parentFile.Id] = parentFile
|
|
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
|
|
// OpenDir return nil error allows open dir
|
|
func (fs *GDriveFS) OpenDir(ctx context.Context, op *fuseops.OpenDirOp) (err error) {
|
|
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 {
|
|
if entry == nil {
|
|
return fuse.ENOENT
|
|
return fuse.ENOENT
|
|
}
|
|
}
|
|
|
|
|
|
- fh := fs.findUnusedHandle()
|
|
|
|
|
|
+ fh := fs.createHandle()
|
|
fh.entry = entry
|
|
fh.entry = entry
|
|
op.Handle = fh.handleID
|
|
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
|
|
if op.Offset == 0 { // Rebuild/rewind dir list
|
|
fh.entries = []fuseutil.Dirent{}
|
|
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
|
|
fusetype := fuseutil.DT_File
|
|
if v.isDir {
|
|
if v.isDir {
|
|
fusetype = fuseutil.DT_Directory
|
|
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)
|
|
index := int(op.Offset)
|
|
if index > len(fh.entries) {
|
|
if index > len(fh.entries) {
|
|
return fuse.EINVAL
|
|
return fuse.EINVAL
|
|
@@ -307,7 +288,6 @@ func (fs *GDriveFS) ReadDir(ctx context.Context, op *fuseops.ReadDirOp) (err err
|
|
if index > 0 {
|
|
if index > 0 {
|
|
index++
|
|
index++
|
|
}
|
|
}
|
|
- count := 0
|
|
|
|
for i := index; i < len(fh.entries); i++ {
|
|
for i := index; i < len(fh.entries); i++ {
|
|
n := fuseutil.WriteDirent(op.Dst[op.BytesRead:], fh.entries[i])
|
|
n := fuseutil.WriteDirent(op.Dst[op.BytesRead:], fh.entries[i])
|
|
//log.Println("Written:", n)
|
|
//log.Println("Written:", n)
|
|
@@ -315,41 +295,7 @@ func (fs *GDriveFS) ReadDir(ctx context.Context, op *fuseops.ReadDirOp) (err err
|
|
break
|
|
break
|
|
}
|
|
}
|
|
op.BytesRead += n
|
|
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
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
@@ -361,7 +307,7 @@ func (fs *GDriveFS) SetInodeAttributes(ctx context.Context, op *fuseops.SetInode
|
|
//GetInodeAttributes return attributes
|
|
//GetInodeAttributes return attributes
|
|
func (fs *GDriveFS) GetInodeAttributes(ctx context.Context, op *fuseops.GetInodeAttributesOp) (err error) {
|
|
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 {
|
|
if f == nil {
|
|
return fuse.ENOENT
|
|
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
|
|
// LookUpInode based on Parent and Name we return a self cached inode
|
|
func (fs *GDriveFS) LookUpInode(ctx context.Context, op *fuseops.LookUpInodeOp) (err error) {
|
|
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 {
|
|
if parentFile == nil {
|
|
return fuse.ENOENT
|
|
return fuse.ENOENT
|
|
}
|
|
}
|
|
|
|
|
|
now := time.Now()
|
|
now := time.Now()
|
|
// Transverse only local
|
|
// Transverse only local
|
|
- f := parentFile.findByName(op.Name, false)
|
|
|
|
|
|
+ f := parentFile.FindByName(op.Name, false)
|
|
if f == nil {
|
|
if f == nil {
|
|
return fuse.ENOENT
|
|
return fuse.ENOENT
|
|
}
|
|
}
|
|
@@ -395,8 +341,8 @@ func (fs *GDriveFS) LookUpInode(ctx context.Context, op *fuseops.LookUpInodeOp)
|
|
op.Entry = fuseops.ChildInodeEntry{
|
|
op.Entry = fuseops.ChildInodeEntry{
|
|
Attributes: f.Attr,
|
|
Attributes: f.Attr,
|
|
Child: f.Inode,
|
|
Child: f.Inode,
|
|
- AttributesExpiration: now.Add(time.Minute),
|
|
|
|
- EntryExpiration: now.Add(time.Minute),
|
|
|
|
|
|
+ AttributesExpiration: now.Add(time.Second),
|
|
|
|
+ EntryExpiration: now.Add(time.Second),
|
|
}
|
|
}
|
|
return
|
|
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
|
|
// OpenFile creates a temporary handle to be handled on read or write
|
|
func (fs *GDriveFS) OpenFile(ctx context.Context, op *fuseops.OpenFileOp) (err error) {
|
|
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
|
|
// Generate new handle
|
|
- fh := fs.findUnusedHandle()
|
|
|
|
|
|
+ fh := fs.createHandle()
|
|
fh.entry = f
|
|
fh.entry = f
|
|
|
|
|
|
op.Handle = fh.handleID
|
|
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) {
|
|
func (fs *GDriveFS) ReadFile(ctx context.Context, op *fuseops.ReadFileOp) (err error) {
|
|
lf := fs.fileHandles[op.Handle]
|
|
lf := fs.fileHandles[op.Handle]
|
|
|
|
|
|
- localFile := lf.entry.cache()
|
|
|
|
|
|
+ localFile := lf.entry.Cache()
|
|
op.BytesRead, err = localFile.ReadAt(op.Dst, op.Offset)
|
|
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
|
|
if err == io.EOF { // fuse does not expect a EOF
|
|
err = nil
|
|
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'
|
|
// 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) {
|
|
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 {
|
|
if parentFile == nil {
|
|
- err = fuse.ENOENT
|
|
|
|
- return
|
|
|
|
|
|
+ return fuse.ENOENT
|
|
}
|
|
}
|
|
// Only write on child folders
|
|
// Only write on child folders
|
|
if parentFile.Inode == fuseops.RootInodeID {
|
|
if parentFile.Inode == fuseops.RootInodeID {
|
|
return syscall.EPERM
|
|
return syscall.EPERM
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ existsFile := parentFile.FindByName(op.Name, false)
|
|
|
|
+ if existsFile != nil {
|
|
|
|
+ return fuse.EEXIST
|
|
|
|
+ }
|
|
|
|
+
|
|
// Generate ID
|
|
// Generate ID
|
|
//genId, err := fs.srv.Files.GenerateIds().Count(1).Do()
|
|
//genId, err := fs.srv.Files.GenerateIds().Count(1).Do()
|
|
//id := genId.Ids[0]
|
|
//id := genId.Ids[0]
|
|
@@ -477,21 +424,20 @@ func (fs *GDriveFS) CreateFile(ctx context.Context, op *fuseops.CreateFileOp) (e
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
- entry := parentFile.appendGFile(createdFile) // Add new created file
|
|
|
|
|
|
+ entry := parentFile.AppendGFile(createdFile, fs.root.FindUnusedInode()) // Add new created file
|
|
if entry == nil {
|
|
if entry == nil {
|
|
err = fuse.EINVAL
|
|
err = fuse.EINVAL
|
|
return
|
|
return
|
|
}
|
|
}
|
|
- log.Println("File Created", entry)
|
|
|
|
|
|
|
|
- localFile := entry.cache()
|
|
|
|
|
|
+ localFile := entry.Cache()
|
|
if localFile == nil {
|
|
if localFile == nil {
|
|
return fuse.EINVAL
|
|
return fuse.EINVAL
|
|
}
|
|
}
|
|
// Associate a temp file to a new handle
|
|
// Associate a temp file to a new handle
|
|
// Local copy
|
|
// Local copy
|
|
// Lock
|
|
// Lock
|
|
- fh := fs.findUnusedHandle()
|
|
|
|
|
|
+ fh := fs.createHandle()
|
|
fh.entry = entry
|
|
fh.entry = entry
|
|
fh.uploadOnDone = true
|
|
fh.uploadOnDone = true
|
|
//
|
|
//
|
|
@@ -516,7 +462,7 @@ func (fs *GDriveFS) WriteFile(ctx context.Context, op *fuseops.WriteFileOp) (err
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
- localFile := lf.entry.cache()
|
|
|
|
|
|
+ localFile := lf.entry.Cache()
|
|
if localFile == nil {
|
|
if localFile == nil {
|
|
return fuse.EINVAL
|
|
return fuse.EINVAL
|
|
}
|
|
}
|
|
@@ -536,21 +482,20 @@ func (fs *GDriveFS) ReleaseFileHandle(ctx context.Context, op *fuseops.ReleaseFi
|
|
lf := fs.fileHandles[op.Handle]
|
|
lf := fs.fileHandles[op.Handle]
|
|
|
|
|
|
if lf.uploadOnDone {
|
|
if lf.uploadOnDone {
|
|
- err = lf.entry.sync()
|
|
|
|
|
|
+ err = lf.entry.Sync()
|
|
if err != nil {
|
|
if err != nil {
|
|
return fuse.EINVAL
|
|
return fuse.EINVAL
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- lf.entry.clearCache()
|
|
|
|
|
|
+ lf.entry.ClearCache()
|
|
delete(fs.fileHandles, op.Handle)
|
|
delete(fs.fileHandles, op.Handle)
|
|
|
|
|
|
- //go fs.refresh()
|
|
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
// Unlink remove file and remove from local cache entry
|
|
// Unlink remove file and remove from local cache entry
|
|
func (fs *GDriveFS) Unlink(ctx context.Context, op *fuseops.UnlinkOp) (err error) {
|
|
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 {
|
|
if parentEntry == nil {
|
|
return fuse.ENOENT
|
|
return fuse.ENOENT
|
|
}
|
|
}
|
|
@@ -558,7 +503,7 @@ func (fs *GDriveFS) Unlink(ctx context.Context, op *fuseops.UnlinkOp) (err error
|
|
return syscall.EPERM
|
|
return syscall.EPERM
|
|
}
|
|
}
|
|
|
|
|
|
- fileEntry := parentEntry.findByName(op.Name, false)
|
|
|
|
|
|
+ fileEntry := parentEntry.FindByName(op.Name, false)
|
|
if fileEntry == nil {
|
|
if fileEntry == nil {
|
|
return fuse.ENOATTR
|
|
return fuse.ENOATTR
|
|
}
|
|
}
|
|
@@ -567,7 +512,7 @@ func (fs *GDriveFS) Unlink(ctx context.Context, op *fuseops.UnlinkOp) (err error
|
|
return fuse.EIO
|
|
return fuse.EIO
|
|
}
|
|
}
|
|
|
|
|
|
- parentEntry.removeEntry(fileEntry)
|
|
|
|
|
|
+ parentEntry.RemoveChild(fileEntry)
|
|
|
|
|
|
return
|
|
return
|
|
}
|
|
}
|
|
@@ -580,7 +525,7 @@ func (fs *GDriveFS) FlushFile(ctx context.Context, op *fuseops.FlushFileOp) (err
|
|
// MkDir creates a directory on a parent dir
|
|
// MkDir creates a directory on a parent dir
|
|
func (fs *GDriveFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) (err error) {
|
|
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 {
|
|
if parentFile == nil {
|
|
return fuse.ENOENT
|
|
return fuse.ENOENT
|
|
}
|
|
}
|
|
@@ -597,7 +542,7 @@ func (fs *GDriveFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) (err error)
|
|
if err != nil {
|
|
if err != nil {
|
|
return fuse.ENOATTR
|
|
return fuse.ENOATTR
|
|
}
|
|
}
|
|
- entry := parentFile.appendGFile(fi)
|
|
|
|
|
|
+ entry := parentFile.AppendGFile(fi, fs.root.FindUnusedInode())
|
|
if entry == nil {
|
|
if entry == nil {
|
|
return fuse.EINVAL
|
|
return fuse.EINVAL
|
|
}
|
|
}
|
|
@@ -615,7 +560,7 @@ func (fs *GDriveFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) (err error)
|
|
// RmDir fuse implementation
|
|
// RmDir fuse implementation
|
|
func (fs *GDriveFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) (err error) {
|
|
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 {
|
|
if parentFile == nil {
|
|
return fuse.ENOENT
|
|
return fuse.ENOENT
|
|
}
|
|
}
|
|
@@ -623,14 +568,14 @@ func (fs *GDriveFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) (err error)
|
|
return syscall.EPERM
|
|
return syscall.EPERM
|
|
}
|
|
}
|
|
|
|
|
|
- theFile := parentFile.findByName(op.Name, false)
|
|
|
|
|
|
+ theFile := parentFile.FindByName(op.Name, false)
|
|
|
|
|
|
err = fs.srv.Files.Delete(theFile.GFile.Id).Do()
|
|
err = fs.srv.Files.Delete(theFile.GFile.Id).Do()
|
|
if err != nil {
|
|
if err != nil {
|
|
return fuse.ENOTEMPTY
|
|
return fuse.ENOTEMPTY
|
|
}
|
|
}
|
|
|
|
|
|
- parentFile.removeEntry(theFile)
|
|
|
|
|
|
+ parentFile.RemoveChild(theFile)
|
|
|
|
|
|
// Remove from entry somehow
|
|
// Remove from entry somehow
|
|
|
|
|
|
@@ -639,11 +584,11 @@ func (fs *GDriveFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) (err error)
|
|
|
|
|
|
// Rename fuse implementation
|
|
// Rename fuse implementation
|
|
func (fs *GDriveFS) Rename(ctx context.Context, op *fuseops.RenameOp) (err error) {
|
|
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 {
|
|
if oldParentFile == nil {
|
|
return fuse.ENOENT
|
|
return fuse.ENOENT
|
|
}
|
|
}
|
|
- newParentFile := fs.root.findByInode(op.NewParent, true)
|
|
|
|
|
|
+ newParentFile := fs.root.FindByInode(op.NewParent, true)
|
|
if newParentFile == nil {
|
|
if newParentFile == nil {
|
|
return fuse.ENOENT
|
|
return fuse.ENOENT
|
|
}
|
|
}
|
|
@@ -652,7 +597,14 @@ func (fs *GDriveFS) Rename(ctx context.Context, op *fuseops.RenameOp) (err error
|
|
return syscall.EPERM
|
|
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{
|
|
ngFile := &drive.File{
|
|
Name: op.NewName,
|
|
Name: op.NewName,
|
|
@@ -665,8 +617,8 @@ func (fs *GDriveFS) Rename(ctx context.Context, op *fuseops.RenameOp) (err error
|
|
}
|
|
}
|
|
updatedFile, err := updateCall.Do()
|
|
updatedFile, err := updateCall.Do()
|
|
|
|
|
|
- oldParentFile.removeEntry(oldFile)
|
|
|
|
- newParentFile.appendGFile(updatedFile)
|
|
|
|
|
|
+ oldParentFile.RemoveChild(oldFile)
|
|
|
|
+ newParentFile.AppendGFile(updatedFile, oldFile.Inode)
|
|
|
|
|
|
return
|
|
return
|
|
|
|
|