filesystem.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. package filesystem
  2. /*
  3. ArOZ Online File System Handler Wrappers
  4. author: tobychui
  5. This is a module design to do the followings
  6. 1. Mount / Create a fs when open
  7. 2. Provide the basic function and operations of a file system type
  8. 3. THIS MODULE **SHOULD NOT CONTAIN** CROSS FILE SYSTEM TYPE OPERATIONS
  9. */
  10. import (
  11. "errors"
  12. "log"
  13. "os"
  14. "path/filepath"
  15. "strings"
  16. "time"
  17. db "imuslab.com/arozos/mod/database"
  18. )
  19. //Options for creating new file system handler
  20. /*
  21. type FileSystemOpeningOptions struct{
  22. Name string `json:"name"` //Display name of this device
  23. Uuid string `json:"uuid"` //UUID of this device, e.g. S1
  24. Path string `json:"path"` //Path for the storage root
  25. Access string `json:"access,omitempty"` //Access right, allow {readonly, readwrite}
  26. Hierarchy string `json:"hierarchy"` //Folder hierarchy, allow {public, user}
  27. Automount bool `json:"automount"` //Automount this device if exists
  28. Filesystem string `json:"filesystem,omitempty"` //Support {"ext4","ext2", "ext3", "fat", "vfat", "ntfs"}
  29. Mountdev string `json:"mountdev,omitempty"` //Device file (e.g. /dev/sda1)
  30. Mountpt string `json:"mountpt,omitempty"` //Device mount point (e.g. /media/storage1)
  31. }
  32. */
  33. //System Handler for returing
  34. type FileSystemHandler struct {
  35. Name string
  36. UUID string
  37. Path string
  38. Hierarchy string
  39. ReadOnly bool
  40. Parentuid string
  41. InitiationTime int64
  42. FilesystemDatabase *db.Database
  43. Filesystem string
  44. Closed bool
  45. }
  46. //Create a list of file system handler from the given json content
  47. func NewFileSystemHandlersFromJSON(jsonContent []byte) ([]*FileSystemHandler, error) {
  48. //Generate a list of handler option from json file
  49. options, err := loadConfigFromJSON(jsonContent)
  50. if err != nil {
  51. return []*FileSystemHandler{}, err
  52. }
  53. resultingHandlers := []*FileSystemHandler{}
  54. for _, option := range options {
  55. thisHandler, err := NewFileSystemHandler(option)
  56. if err != nil {
  57. log.Println("Failed to create system handler for " + option.Name)
  58. log.Println(err.Error())
  59. continue
  60. }
  61. resultingHandlers = append(resultingHandlers, thisHandler)
  62. }
  63. return resultingHandlers, nil
  64. }
  65. //Create a new file system handler with the given config
  66. func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
  67. fstype := strings.ToLower(option.Filesystem)
  68. if inSlice([]string{"ext4", "ext2", "ext3", "fat", "vfat", "ntfs"}, fstype) || fstype == "" {
  69. //Check if the target fs require mounting
  70. if option.Automount == true {
  71. err := MountDevice(option.Mountpt, option.Mountdev, option.Filesystem)
  72. if err != nil {
  73. return &FileSystemHandler{}, err
  74. }
  75. }
  76. //Check if the path exists
  77. if !fileExists(option.Path) {
  78. return &FileSystemHandler{}, errors.New("Mount point not exists!")
  79. }
  80. if option.Hierarchy == "user" {
  81. //Create user hierarchy for this virtual device
  82. os.MkdirAll(filepath.ToSlash(filepath.Clean(option.Path))+"/users", 0755)
  83. }
  84. //Create the fsdb for this handler
  85. fsdb, err := db.NewDatabase(filepath.ToSlash(filepath.Join(filepath.Clean(option.Path), "aofs.db")), false)
  86. if err != nil {
  87. return &FileSystemHandler{}, errors.New("Unable to create fsdb inside the target path. Is the directory read only?")
  88. }
  89. if option.Hierarchy == "backup" {
  90. //This is a backup drive.
  91. }
  92. return &FileSystemHandler{
  93. Name: option.Name,
  94. UUID: option.Uuid,
  95. Path: filepath.ToSlash(filepath.Clean(option.Path)) + "/",
  96. ReadOnly: option.Access == "readonly",
  97. Parentuid: option.Parentuid,
  98. Hierarchy: option.Hierarchy,
  99. InitiationTime: time.Now().Unix(),
  100. FilesystemDatabase: fsdb,
  101. Filesystem: fstype,
  102. Closed: false,
  103. }, nil
  104. }
  105. return nil, errors.New("Not supported file system: " + fstype)
  106. }
  107. //Create a file ownership record
  108. func (fsh *FileSystemHandler) CreateFileRecord(realpath string, owner string) error {
  109. rpabs, _ := filepath.Abs(realpath)
  110. fsrabs, _ := filepath.Abs(fsh.Path)
  111. reldir, err := filepath.Rel(fsrabs, rpabs)
  112. if err != nil {
  113. return err
  114. }
  115. fsh.FilesystemDatabase.NewTable("owner")
  116. fsh.FilesystemDatabase.Write("owner", "owner/"+reldir, owner)
  117. return nil
  118. }
  119. //Read the owner of a file
  120. func (fsh *FileSystemHandler) GetFileRecord(realpath string) (string, error) {
  121. rpabs, _ := filepath.Abs(realpath)
  122. fsrabs, _ := filepath.Abs(fsh.Path)
  123. reldir, err := filepath.Rel(fsrabs, rpabs)
  124. if err != nil {
  125. return "", err
  126. }
  127. fsh.FilesystemDatabase.NewTable("owner")
  128. if fsh.FilesystemDatabase.KeyExists("owner", "owner/"+reldir) {
  129. owner := ""
  130. fsh.FilesystemDatabase.Read("owner", "owner/"+reldir, &owner)
  131. return owner, nil
  132. } else {
  133. return "", errors.New("Owner not exists")
  134. }
  135. }
  136. //Delete a file ownership record
  137. func (fsh *FileSystemHandler) DeleteFileRecord(realpath string) error {
  138. rpabs, _ := filepath.Abs(realpath)
  139. fsrabs, _ := filepath.Abs(fsh.Path)
  140. reldir, err := filepath.Rel(fsrabs, rpabs)
  141. if err != nil {
  142. return err
  143. }
  144. fsh.FilesystemDatabase.NewTable("owner")
  145. if fsh.FilesystemDatabase.KeyExists("owner", "owner/"+reldir) {
  146. fsh.FilesystemDatabase.Delete("owner", "owner/"+reldir)
  147. }
  148. return nil
  149. }
  150. func (fsh *FileSystemHandler) Close() {
  151. fsh.FilesystemDatabase.Close()
  152. }
  153. //Helper function
  154. func inSlice(slice []string, val string) bool {
  155. for _, item := range slice {
  156. if item == val {
  157. return true
  158. }
  159. }
  160. return false
  161. }
  162. func FileExists(filename string) bool {
  163. return fileExists(filename)
  164. }
  165. //Check if file exists
  166. func fileExists(filename string) bool {
  167. _, err := os.Stat(filename)
  168. if os.IsNotExist(err) {
  169. return false
  170. }
  171. return true
  172. }