storage.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. package main
  2. import (
  3. "errors"
  4. "io/ioutil"
  5. "log"
  6. "os"
  7. "path/filepath"
  8. "runtime"
  9. "strings"
  10. "imuslab.com/arozos/mod/filesystem/fsdef"
  11. "imuslab.com/arozos/mod/permission"
  12. "imuslab.com/arozos/mod/storage/bridge"
  13. fs "imuslab.com/arozos/mod/filesystem"
  14. storage "imuslab.com/arozos/mod/storage"
  15. )
  16. var (
  17. baseStoragePool *storage.StoragePool //base storage pool, all user can access these virtual roots
  18. //fsHandlers []*fs.FileSystemHandler //All File system handlers. All opened handles must be registered in here
  19. //storagePools []*storage.StoragePool //All Storage pool opened
  20. bridgeManager *bridge.Record //Manager to handle bridged FSH
  21. )
  22. func StorageInit() {
  23. //Load the default handler for the user storage root
  24. if !fs.FileExists(filepath.Clean(*root_directory) + "/") {
  25. os.MkdirAll(filepath.Clean(*root_directory)+"/", 0755)
  26. }
  27. //Start loading the base storage pool
  28. err := LoadBaseStoragePool()
  29. if err != nil {
  30. panic(err)
  31. }
  32. //Create a brdige record manager
  33. bm := bridge.NewBridgeRecord("system/bridge.json")
  34. bridgeManager = bm
  35. }
  36. func LoadBaseStoragePool() error {
  37. //All fsh for the base pool
  38. fsHandlers := []*fs.FileSystemHandler{}
  39. //Use for Debian buster local file system
  40. localFileSystem := "ext4"
  41. if runtime.GOOS == "windows" {
  42. localFileSystem = "ntfs"
  43. }
  44. baseHandler, err := fs.NewFileSystemHandler(fs.FileSystemOption{
  45. Name: "User",
  46. Uuid: "user",
  47. Path: filepath.ToSlash(filepath.Clean(*root_directory)) + "/",
  48. Hierarchy: "user",
  49. Automount: false,
  50. Filesystem: localFileSystem,
  51. })
  52. if err != nil {
  53. log.Println("Failed to initiate user root storage directory: "+*root_directory, err.Error())
  54. return err
  55. }
  56. fsHandlers = append(fsHandlers, baseHandler)
  57. //Load the tmp folder as storage unit
  58. tmpHandler, err := fs.NewFileSystemHandler(fs.FileSystemOption{
  59. Name: "tmp",
  60. Uuid: "tmp",
  61. Path: filepath.ToSlash(filepath.Clean(*tmp_directory)) + "/",
  62. Hierarchy: "user",
  63. Automount: false,
  64. Filesystem: localFileSystem,
  65. })
  66. if err != nil {
  67. log.Println("Failed to initiate tmp storage directory: "+*tmp_directory, err.Error())
  68. return err
  69. }
  70. fsHandlers = append(fsHandlers, tmpHandler)
  71. //Load all the storage config from file
  72. rawConfig, err := ioutil.ReadFile(*storage_config_file)
  73. if err != nil {
  74. //File not found. Use internal storage only
  75. log.Println("Storage configuration file not found. Using internal storage only.")
  76. } else {
  77. //Configuration loaded. Initializing handler
  78. externalHandlers, err := fs.NewFileSystemHandlersFromJSON(rawConfig)
  79. if err != nil {
  80. log.Println("Failed to load storage configuration: " + err.Error() + " -- Skipping")
  81. } else {
  82. for _, thisHandler := range externalHandlers {
  83. fsHandlers = append(fsHandlers, thisHandler)
  84. log.Println(thisHandler.Name + " Mounted as " + thisHandler.UUID + ":/")
  85. }
  86. }
  87. }
  88. //Create a base storage pool for all users
  89. sp, err := storage.NewStoragePool(fsHandlers, "system")
  90. if err != nil {
  91. log.Println("Failed to create base Storaeg Pool")
  92. return err
  93. }
  94. //Update the storage pool permission to readwrite
  95. sp.OtherPermission = fsdef.FsReadWrite
  96. baseStoragePool = sp
  97. return nil
  98. }
  99. //Initialize group storage pool
  100. func GroupStoragePoolInit() {
  101. //Mount permission groups
  102. for _, pg := range permissionHandler.PermissionGroups {
  103. //For each group, check does this group has a config file
  104. err := LoadStoragePoolForGroup(pg)
  105. if err != nil {
  106. continue
  107. }
  108. //Do something else, WIP
  109. }
  110. //Start editing interface for Storage Pool Editor
  111. StoragePoolEditorInit()
  112. }
  113. func LoadStoragePoolForGroup(pg *permission.PermissionGroup) error {
  114. expectedConfigPath := "./system/storage/" + pg.Name + ".json"
  115. if fs.FileExists(expectedConfigPath) {
  116. //Read the config file
  117. pgStorageConfig, err := os.ReadFile(expectedConfigPath)
  118. if err != nil {
  119. log.Println("Failed to read config for " + pg.Name + ": " + err.Error())
  120. return errors.New("Failed to read config for " + pg.Name + ": " + err.Error())
  121. }
  122. //Generate fsHandler form json
  123. thisGroupFsHandlers, err := fs.NewFileSystemHandlersFromJSON(pgStorageConfig)
  124. if err != nil {
  125. log.Println("Failed to load storage configuration: " + err.Error())
  126. return errors.New("Failed to load storage configuration: " + err.Error())
  127. }
  128. //Show debug message
  129. for _, thisHandler := range thisGroupFsHandlers {
  130. log.Println(thisHandler.Name + " Mounted as " + thisHandler.UUID + ":/ for group " + pg.Name)
  131. }
  132. //Create a storage pool from these handlers
  133. sp, err := storage.NewStoragePool(thisGroupFsHandlers, pg.Name)
  134. if err != nil {
  135. log.Println("Failed to create storage pool for " + pg.Name)
  136. return errors.New("Failed to create storage pool for " + pg.Name)
  137. }
  138. //Set other permission to denied by default
  139. sp.OtherPermission = fsdef.FsDenied
  140. //Assign storage pool to group
  141. pg.StoragePool = sp
  142. } else {
  143. //Storage configuration not exists. Fill in the basic information and move to next storage pool
  144. //Create a new empty storage pool for this group
  145. sp, err := storage.NewStoragePool([]*fs.FileSystemHandler{}, pg.Name)
  146. if err != nil {
  147. log.Println("Failed to create empty storage pool for group: ", pg.Name)
  148. }
  149. pg.StoragePool = sp
  150. pg.StoragePool.OtherPermission = fsdef.FsDenied
  151. }
  152. return nil
  153. }
  154. //Check if a storage pool exists by its group owner name
  155. func StoragePoolExists(poolOwner string) bool {
  156. _, err := GetStoragePoolByOwner(poolOwner)
  157. return err == nil
  158. }
  159. func GetAllStoragePools() []*storage.StoragePool {
  160. //Append the base pool
  161. results := []*storage.StoragePool{baseStoragePool}
  162. //Add each permissionGroup's pool
  163. for _, pg := range permissionHandler.PermissionGroups {
  164. results = append(results, pg.StoragePool)
  165. }
  166. return results
  167. }
  168. func GetStoragePoolByOwner(owner string) (*storage.StoragePool, error) {
  169. sps := GetAllStoragePools()
  170. for _, pool := range sps {
  171. if pool.Owner == owner {
  172. return pool, nil
  173. }
  174. }
  175. return nil, errors.New("Storage pool owned by " + owner + " not found")
  176. }
  177. func GetFSHandlerSubpathFromVpath(vpath string) (*fs.FileSystemHandler, string, error) {
  178. VirtualRootID, subpath, err := fs.GetIDFromVirtualPath(vpath)
  179. if err != nil {
  180. return nil, "", errors.New("Unable to resolve requested path: " + err.Error())
  181. }
  182. fsh, err := GetFsHandlerByUUID(VirtualRootID)
  183. if err != nil {
  184. return nil, "", errors.New("Unable to resolve requested path: " + err.Error())
  185. }
  186. if fsh == nil || fsh.FileSystemAbstraction == nil {
  187. return nil, "", errors.New("Unable to resolve requested path: " + err.Error())
  188. }
  189. return fsh, subpath, nil
  190. }
  191. func GetFsHandlerByUUID(uuid string) (*fs.FileSystemHandler, error) {
  192. //Filter out the :/ fropm uuid if exists
  193. if strings.Contains(uuid, ":") {
  194. uuid = strings.Split(uuid, ":")[0]
  195. }
  196. var resultFsh *fs.FileSystemHandler = nil
  197. allFsh := GetAllLoadedFsh()
  198. for _, fsh := range allFsh {
  199. if fsh.UUID == uuid && !fsh.Closed {
  200. resultFsh = fsh
  201. }
  202. }
  203. if resultFsh == nil {
  204. return nil, errors.New("Filesystem handler with given UUID not found")
  205. } else {
  206. return resultFsh, nil
  207. }
  208. }
  209. func GetAllLoadedFsh() []*fs.FileSystemHandler {
  210. fshTmp := map[string]*fs.FileSystemHandler{}
  211. allFsh := []*fs.FileSystemHandler{}
  212. allStoragePools := GetAllStoragePools()
  213. for _, thisSP := range allStoragePools {
  214. for _, thisFsh := range thisSP.Storages {
  215. fshPointer := thisFsh
  216. fshTmp[thisFsh.UUID] = fshPointer
  217. }
  218. }
  219. //Restructure the map to slice
  220. for _, fsh := range fshTmp {
  221. allFsh = append(allFsh, fsh)
  222. }
  223. return allFsh
  224. }
  225. func RegisterStorageSettings() {
  226. //Storage Pool Configuration
  227. registerSetting(settingModule{
  228. Name: "Storage Pools",
  229. Desc: "Storage Pool Mounting Configuration",
  230. IconPath: "SystemAO/disk/smart/img/small_icon.png",
  231. Group: "Disk",
  232. StartDir: "SystemAO/storage/poolList.html",
  233. RequireAdmin: true,
  234. })
  235. }
  236. //CloseAllStorages Close all storage database
  237. func CloseAllStorages() {
  238. allFsh := GetAllLoadedFsh()
  239. for _, fsh := range allFsh {
  240. fsh.FilesystemDatabase.Close()
  241. }
  242. }
  243. func closeAllStoragePools() {
  244. for _, sp := range GetAllStoragePools() {
  245. sp.Close()
  246. }
  247. }