file_container.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package gdrivefs
  2. import (
  3. "fmt"
  4. "os"
  5. "strings"
  6. "sync"
  7. drive "google.golang.org/api/drive/v3"
  8. "github.com/jacobsa/fuse/fuseops"
  9. )
  10. type FileContainer struct {
  11. fileEntries map[fuseops.InodeID]*FileEntry
  12. tree *FileEntry
  13. fs *GDriveFS
  14. uid uint32
  15. gid uint32
  16. inodeMU *sync.Mutex
  17. }
  18. func NewFileContainer(fs *GDriveFS) *FileContainer {
  19. fc := &FileContainer{
  20. fileEntries: map[fuseops.InodeID]*FileEntry{},
  21. fs: fs,
  22. inodeMU: &sync.Mutex{},
  23. uid: fs.config.UID,
  24. gid: fs.config.GID,
  25. }
  26. rootEntry := fc.FileEntry(nil, fuseops.RootInodeID)
  27. rootEntry.Attr.Mode = os.FileMode(0755) | os.ModeDir
  28. fc.tree = rootEntry
  29. return fc
  30. }
  31. func (fc *FileContainer) FindByInode(inode fuseops.InodeID) *FileEntry {
  32. return fc.fileEntries[inode]
  33. }
  34. func (fc *FileContainer) FindByGID(gid string) *FileEntry {
  35. for _, v := range fc.fileEntries {
  36. if v.GFile != nil && v.GFile.Id == gid {
  37. return v
  38. }
  39. }
  40. return nil
  41. }
  42. func (fc *FileContainer) LookupByGID(parentGID string, name string) *FileEntry {
  43. for _, entry := range fc.fileEntries {
  44. if entry.HasParentGID(parentGID) && entry.Name == name {
  45. return entry
  46. }
  47. }
  48. return nil
  49. }
  50. func (fc *FileContainer) ListByParentGID(parentGID string) []*FileEntry {
  51. ret := []*FileEntry{}
  52. for _, entry := range fc.fileEntries {
  53. if entry.HasParentGID(parentGID) {
  54. ret = append(ret, entry)
  55. }
  56. }
  57. return ret
  58. }
  59. //Return or create inode // Pass name maybe?
  60. func (fc *FileContainer) FileEntry(gfile *drive.File, inodeOps ...fuseops.InodeID) *FileEntry {
  61. fc.inodeMU.Lock()
  62. defer fc.inodeMU.Unlock()
  63. var inode fuseops.InodeID
  64. if len(inodeOps) > 0 {
  65. inode = inodeOps[0]
  66. if fe, ok := fc.fileEntries[inode]; ok {
  67. return fe
  68. }
  69. } else { // generate new inode
  70. // Max Inode Number
  71. for inode = 2; inode < 99999; inode++ {
  72. _, ok := fc.fileEntries[inode]
  73. if !ok {
  74. break
  75. }
  76. }
  77. }
  78. name := ""
  79. if gfile != nil {
  80. name = gfile.Name
  81. count := 1
  82. nameParts := strings.Split(name, ".")
  83. for {
  84. // We find if we have a GFile in same parent with same name
  85. var entry *FileEntry
  86. for _, p := range gfile.Parents {
  87. entry = fc.LookupByGID(p, name)
  88. if entry != nil {
  89. break
  90. }
  91. }
  92. if entry == nil { // Not found return
  93. break
  94. }
  95. count++
  96. if len(nameParts) > 1 {
  97. name = fmt.Sprintf("%s(%d).%s", nameParts[0], count, strings.Join(nameParts[1:], "."))
  98. } else {
  99. name = fmt.Sprintf("%s(%d)", nameParts[0], count)
  100. }
  101. log.Printf("Conflicting name generated new '%s' as '%s'", gfile.Name, name)
  102. }
  103. }
  104. fe := &FileEntry{
  105. GFile: gfile,
  106. Inode: inode,
  107. container: fc,
  108. Name: name,
  109. //children: []*FileEntry{},
  110. Attr: fuseops.InodeAttributes{
  111. Uid: fc.uid,
  112. Gid: fc.gid,
  113. },
  114. }
  115. fe.SetGFile(gfile)
  116. fc.fileEntries[inode] = fe
  117. return fe
  118. }
  119. func (fc *FileContainer) AddEntry(entry *FileEntry) {
  120. fc.fileEntries[entry.Inode] = entry
  121. }
  122. // RemoveEntry remove file entry
  123. func (fc *FileContainer) RemoveEntry(entry *FileEntry) {
  124. var inode fuseops.InodeID
  125. for k, e := range fc.fileEntries {
  126. if e == entry {
  127. inode = k
  128. }
  129. }
  130. delete(fc.fileEntries, inode)
  131. }
  132. func (fc *FileContainer) AddGFile(gfile *drive.File) *FileEntry {
  133. entry := fc.FindByGID(gfile.Id)
  134. if entry != nil {
  135. return entry
  136. }
  137. // Create new Entry
  138. entry = fc.FileEntry(gfile)
  139. entry.SetGFile(gfile)
  140. return entry
  141. }