storage.go 8.3 KB

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