filesystem.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. InitiationTime int64
  41. FilesystemDatabase *db.Database
  42. Filesystem string
  43. Closed bool
  44. }
  45. //Create a list of file system handler from the given json content
  46. func NewFileSystemHandlersFromJSON(jsonContent []byte) ([]*FileSystemHandler, error) {
  47. //Generate a list of handler option from json file
  48. options, err := loadConfigFromJSON(jsonContent)
  49. if err != nil {
  50. return []*FileSystemHandler{}, err
  51. }
  52. resultingHandlers := []*FileSystemHandler{}
  53. for _, option := range options {
  54. thisHandler, err := NewFileSystemHandler(option)
  55. if err != nil {
  56. log.Println("Failed to create system handler for " + option.Name)
  57. log.Println(err.Error())
  58. continue
  59. }
  60. resultingHandlers = append(resultingHandlers, thisHandler)
  61. }
  62. return resultingHandlers, nil
  63. }
  64. //Create a new file system handler with the given config
  65. func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
  66. fstype := strings.ToLower(option.Filesystem)
  67. if inSlice([]string{"ext4", "ext2", "ext3", "fat", "vfat", "ntfs"}, fstype) || fstype == "" {
  68. //Check if the target fs require mounting
  69. if option.Automount == true {
  70. err := MountDevice(option.Mountpt, option.Mountdev, option.Filesystem)
  71. if err != nil {
  72. return &FileSystemHandler{}, err
  73. }
  74. }
  75. //Check if the path exists
  76. if !fileExists(option.Path) {
  77. return &FileSystemHandler{}, errors.New("Mount point not exists!")
  78. }
  79. if option.Hierarchy == "user" {
  80. //Create user hierarchy for this virtual device
  81. os.MkdirAll(filepath.ToSlash(filepath.Clean(option.Path))+"/users", 0755)
  82. }
  83. //Create the fsdb for this handler
  84. fsdb, err := db.NewDatabase(filepath.ToSlash(filepath.Clean(option.Path))+"/aofs.db", false)
  85. if err != nil {
  86. return &FileSystemHandler{}, errors.New("Unable to create fsdb inside the target path. Is the directory read only?")
  87. }
  88. return &FileSystemHandler{
  89. Name: option.Name,
  90. UUID: option.Uuid,
  91. Path: filepath.ToSlash(filepath.Clean(option.Path)) + "/",
  92. ReadOnly: option.Access == "readonly",
  93. Hierarchy: option.Hierarchy,
  94. InitiationTime: time.Now().Unix(),
  95. FilesystemDatabase: fsdb,
  96. Filesystem: fstype,
  97. Closed: false,
  98. }, nil
  99. }
  100. return nil, errors.New("Not supported file system: " + fstype)
  101. }
  102. //Create a file ownership record
  103. func (fsh *FileSystemHandler) CreateFileRecord(realpath string, owner string) error {
  104. rpabs, _ := filepath.Abs(realpath)
  105. fsrabs, _ := filepath.Abs(fsh.Path)
  106. reldir, err := filepath.Rel(fsrabs, rpabs)
  107. if err != nil {
  108. return err
  109. }
  110. fsh.FilesystemDatabase.NewTable("owner")
  111. fsh.FilesystemDatabase.Write("owner", "owner/"+reldir, owner)
  112. return nil
  113. }
  114. //Read the owner of a file
  115. func (fsh *FileSystemHandler) GetFileRecord(realpath string) (string, error) {
  116. rpabs, _ := filepath.Abs(realpath)
  117. fsrabs, _ := filepath.Abs(fsh.Path)
  118. reldir, err := filepath.Rel(fsrabs, rpabs)
  119. if err != nil {
  120. return "", err
  121. }
  122. fsh.FilesystemDatabase.NewTable("owner")
  123. if fsh.FilesystemDatabase.KeyExists("owner", "owner/"+reldir) {
  124. owner := ""
  125. fsh.FilesystemDatabase.Read("owner", "owner/"+reldir, &owner)
  126. return owner, nil
  127. } else {
  128. return "", errors.New("Owner not exists")
  129. }
  130. }
  131. //Delete a file ownership record
  132. func (fsh *FileSystemHandler) DeleteFileRecord(realpath string) error {
  133. rpabs, _ := filepath.Abs(realpath)
  134. fsrabs, _ := filepath.Abs(fsh.Path)
  135. reldir, err := filepath.Rel(fsrabs, rpabs)
  136. if err != nil {
  137. return err
  138. }
  139. fsh.FilesystemDatabase.NewTable("owner")
  140. if fsh.FilesystemDatabase.KeyExists("owner", "owner/"+reldir) {
  141. fsh.FilesystemDatabase.Delete("owner", "owner/"+reldir)
  142. }
  143. return nil
  144. }
  145. func (fsh *FileSystemHandler) Close() {
  146. fsh.FilesystemDatabase.Close()
  147. }
  148. //Helper function
  149. func inSlice(slice []string, val string) bool {
  150. for _, item := range slice {
  151. if item == val {
  152. return true
  153. }
  154. }
  155. return false
  156. }
  157. func FileExists(filename string) bool {
  158. return fileExists(filename)
  159. }
  160. //Check if file exists
  161. func fileExists(filename string) bool {
  162. _, err := os.Stat(filename)
  163. if os.IsNotExist(err) {
  164. return false
  165. }
  166. return true
  167. }