Pārlūkot izejas kodu

Fixed bug in R2V translator in webdav driver

Toby Chui 3 gadi atpakaļ
vecāks
revīzija
2360e6660b
43 mainītis faili ar 589 papildinājumiem un 616 dzēšanām
  1. 0 0
      backup.go.disabled
  2. 83 95
      file_system.go
  3. 0 0
      legacy/_hybridBackup/basicBackup.go
  4. 0 0
      legacy/_hybridBackup/compareRoots.go
  5. 0 0
      legacy/_hybridBackup/doc.txt
  6. 0 0
      legacy/_hybridBackup/fastwalk.go
  7. 0 0
      legacy/_hybridBackup/fileUtil.go
  8. 0 0
      legacy/_hybridBackup/hybridBackup.go
  9. 0 0
      legacy/_hybridBackup/linker.go
  10. 0 0
      legacy/_hybridBackup/snaoshotOpr.go
  11. 0 0
      legacy/_hybridBackup/versionBackup.go
  12. 5 5
      mediaServer.go
  13. 5 5
      mod/agi/agi.file.go
  14. 3 9
      mod/agi/agi.http.go
  15. 6 7
      mod/disk/diskcapacity/dftool/dftool.go
  16. 42 3
      mod/disk/diskcapacity/diskcapacity.go
  17. 8 4
      mod/disk/sortfile/sortfile.go
  18. 22 22
      mod/filesystem/abstractions/emptyfs/emptyfs.go
  19. 3 3
      mod/filesystem/abstractions/localfs/localfs.go
  20. 4 0
      mod/filesystem/abstractions/webdavfs/webdavfs.go
  21. 5 3
      mod/filesystem/config.go
  22. 1 1
      mod/filesystem/fileOpr.go
  23. 47 82
      mod/filesystem/filesystem.go
  24. 13 2
      mod/filesystem/fsdef/fsdef.go
  25. 52 42
      mod/filesystem/fspermission/fspermission.go
  26. 2 2
      mod/filesystem/static.go
  27. 0 13
      mod/info/hardwareinfo/hardwareinfo.go
  28. 1 0
      mod/info/hardwareinfo/sysinfo_freebsd.go
  29. 5 4
      mod/share/share.go
  30. 1 14
      mod/share/shareEntry/shareEntry.go
  31. 155 184
      mod/storage/ftp/aofs.go
  32. 11 42
      mod/storage/storage.go
  33. 9 3
      mod/time/scheduler/handlers.go
  34. 8 7
      mod/time/scheduler/scheduler.go
  35. 4 1
      mod/user/directoryHandler.go
  36. 10 9
      mod/user/permissionHandler.go
  37. 22 24
      mod/user/quota.go
  38. 23 15
      mod/www/www.go
  39. 1 1
      startup.go
  40. 23 5
      storage.go
  41. 1 1
      web/Music/embedded.html
  42. 11 5
      web/SystemAO/disk/diskprop.html
  43. 3 3
      web/SystemAO/locale/disk_properties.json

+ 0 - 0
backup.go → backup.go.disabled


+ 83 - 95
file_system.go

@@ -24,9 +24,9 @@ import (
 
 	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/compatibility"
-	"imuslab.com/arozos/mod/disk/hybridBackup"
 	"imuslab.com/arozos/mod/filesystem"
 	fs "imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/filesystem/fsdef"
 	fsp "imuslab.com/arozos/mod/filesystem/fspermission"
 	"imuslab.com/arozos/mod/filesystem/fuzzy"
 	hidden "imuslab.com/arozos/mod/filesystem/hidden"
@@ -88,7 +88,6 @@ func FileSystemInit() {
 	router.HandleFunc("/system/file_system/restoreTrash", system_fs_restoreFile)
 	router.HandleFunc("/system/file_system/zipHandler", system_fs_zipHandler)
 	router.HandleFunc("/system/file_system/getProperties", system_fs_getFileProperties)
-	router.HandleFunc("/system/file_system/pathTranslate", system_fs_handlePathTranslate)
 	router.HandleFunc("/system/file_system/versionHistory", system_fs_FileVersionHistory)
 
 	router.HandleFunc("/system/file_system/handleFilePermission", system_fs_handleFilePermission)
@@ -394,10 +393,10 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	targetFs := fsh.FileSystemAbstraction
+	fshAbs := fsh.FileSystemAbstraction
 
 	//Translate the upload target directory
-	realUploadPath, err := targetFs.VirtualPathToRealPath(subpath, userinfo.Username)
+	realUploadPath, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
 	if err != nil {
 		w.WriteHeader(http.StatusInternalServerError)
 		w.Write([]byte("500 - Path translation failed"))
@@ -413,8 +412,8 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 	}
 
 	targetUploadLocation := filepath.Join(realUploadPath, filename)
-	if !targetFs.FileExists(realUploadPath) {
-		targetFs.MkdirAll(realUploadPath, 0755)
+	if !fshAbs.FileExists(realUploadPath) {
+		fshAbs.MkdirAll(realUploadPath, 0755)
 	}
 
 	//Generate an UUID for this upload
@@ -423,7 +422,7 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 	if isHugeFile {
 		//Upload to the same directory as the target location. This option do not allow buffered fs
 		uploadFolder = filepath.Join(realUploadPath, ".metadata/.upload", uploadUUID)
-		targetFs.MkdirAll(uploadFolder, 0700)
+		fshAbs.MkdirAll(uploadFolder, 0700)
 	} else {
 		//Buffer to local tmp folder
 		os.MkdirAll(uploadFolder, 0700)
@@ -475,7 +474,11 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 			log.Println("Upload terminated by client. Cleaning tmp folder.")
 			//Clear the tmp folder
 			time.Sleep(1 * time.Second)
-			os.RemoveAll(uploadFolder)
+			if isHugeFile {
+				fshAbs.RemoveAll(uploadFolder)
+			} else {
+				os.RemoveAll(uploadFolder)
+			}
 			return
 		}
 		//The mt should be 2 = binary for file upload and 1 for control syntax
@@ -505,7 +508,11 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 				c.Close()
 
 				//Clear the tmp files
-				os.RemoveAll(uploadFolder)
+				if isHugeFile {
+					fshAbs.RemoveAll(uploadFolder)
+				} else {
+					os.RemoveAll(uploadFolder)
+				}
 				return
 			}
 
@@ -524,7 +531,11 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 				c.Close()
 
 				//Clear the tmp files
-				os.RemoveAll(uploadFolder)
+				if isHugeFile {
+					fshAbs.RemoveAll(uploadFolder)
+				} else {
+					os.RemoveAll(uploadFolder)
+				}
 
 				return
 			} else if !userinfo.StorageQuota.HaveSpace(totalFileSize) {
@@ -537,7 +548,11 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 				c.Close()
 
 				//Clear the tmp files
-				os.RemoveAll(uploadFolder)
+				if isHugeFile {
+					fshAbs.RemoveAll(uploadFolder)
+				} else {
+					os.RemoveAll(uploadFolder)
+				}
 			}
 			blockCounter++
 
@@ -589,6 +604,21 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 
 	out.Close()
 
+	//Check if the size fit in user quota
+	fi, err := os.Stat(mergeFileLocation)
+	if err != nil {
+		// Could not obtain stat, handle error
+		log.Println("Failed to validate uploaded file: ", mergeFileLocation, ". Error Message: ", err.Error())
+		c.WriteMessage(1, []byte(`{\"error\":\"Failed to validate uploaded file\"}`))
+		return
+	}
+	if !userinfo.StorageQuota.HaveSpace(fi.Size()) {
+		c.WriteMessage(1, []byte(`{\"error\":\"User Storage Quota Exceeded\"}`))
+		os.RemoveAll(mergeFileLocation)
+		return
+	}
+
+	//Upload it to remote side if it fits the user quota && is buffer file
 	if fsh.RequireBuffer && !isHugeFile {
 		//This is buffer file. Upload to dest fsh
 		f, err := os.Open(mergeFileLocation)
@@ -612,26 +642,11 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 		os.Remove(mergeFileLocation)
 	}
 
-	//Check if the size fit in user quota
-	fi, err := targetFs.Stat(decodedUploadLocation)
-	if err != nil {
-		// Could not obtain stat, handle error
-		log.Println("Failed to validate uploaded file: ", decodedUploadLocation, ". Error Message: ", err.Error())
-		c.WriteMessage(1, []byte(`{\"error\":\"Failed to validate uploaded file\"}`))
-		return
-	}
-
-	if !userinfo.StorageQuota.HaveSpace(fi.Size()) {
-		c.WriteMessage(1, []byte(`{\"error\":\"User Storage Quota Exceeded\"}`))
-		os.RemoveAll(decodedUploadLocation)
-		return
-	}
-
 	//Log the upload filename
 	log.Println(userinfo.Username + " uploaded a file: " + filepath.Base(decodedUploadLocation))
 
 	//Set owner of the new uploaded file
-	userinfo.SetOwnerOfFile(decodedUploadLocation)
+	userinfo.SetOwnerOfFile(fsh, unescapedPath)
 
 	//Return complete signal
 	c.WriteMessage(1, []byte("OK"))
@@ -642,7 +657,7 @@ func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
 	//Clear the tmp folder
 	time.Sleep(300 * time.Millisecond)
 	if isHugeFile {
-		targetFs.RemoveAll(uploadFolder)
+		fshAbs.RemoveAll(uploadFolder)
 	} else {
 		os.RemoveAll(uploadFolder)
 	}
@@ -745,10 +760,10 @@ func system_fs_handleUpload(w http.ResponseWriter, r *http.Request) {
 
 	//Check if the upload target is read only.
 	accmode := userinfo.GetPathAccessPermission(uploadTarget)
-	if accmode == "readonly" {
+	if accmode == fsdef.FsReadOnly {
 		common.SendErrorResponse(w, "The upload target is Read Only.")
 		return
-	} else if accmode == "denied" {
+	} else if accmode == fsdef.FsDenied {
 		common.SendErrorResponse(w, "Access Denied")
 		return
 	}
@@ -779,7 +794,7 @@ func system_fs_handleUpload(w http.ResponseWriter, r *http.Request) {
 	r.MultipartForm.RemoveAll()
 
 	//Set the ownership of file
-	userinfo.SetOwnerOfFile(destFilepath)
+	userinfo.SetOwnerOfFile(fsh, uploadTarget)
 
 	//Finish up the upload
 	/*
@@ -1057,10 +1072,11 @@ func system_fs_clearTrashBin(w http.ResponseWriter, r *http.Request) {
 
 	//Get list success. Remove each of them.
 	for c, file := range fileList {
-		isOwner := u.IsOwnerOfFile(file)
+		fileVpath, _ := fshs[c].FileSystemAbstraction.RealPathToVirtualPath(file, u.Username)
+		isOwner := u.IsOwnerOfFile(fshs[c], fileVpath)
 		if isOwner {
 			//This user own this system. Remove this file from his quota
-			u.RemoveOwnershipFromFile(file)
+			u.RemoveOwnershipFromFile(fshs[c], fileVpath)
 		}
 		fshAbs := fshs[c].FileSystemAbstraction
 		fshAbs.RemoveAll(file)
@@ -1187,10 +1203,10 @@ func system_fs_handleNewObjects(w http.ResponseWriter, r *http.Request) {
 
 		//Check if directory is readonly
 		accmode := userinfo.GetPathAccessPermission(vsrc)
-		if accmode == "readonly" {
+		if accmode == fsdef.FsReadOnly {
 			common.SendErrorResponse(w, "This directory is Read Only")
 			return
-		} else if accmode == "denied" {
+		} else if accmode == fsdef.FsDenied {
 			common.SendErrorResponse(w, "Access Denied")
 			return
 		}
@@ -1782,10 +1798,10 @@ func system_fs_handleOpr(w http.ResponseWriter, r *http.Request) {
 
 				//Check if the target dir is not readonly
 				accmode := userinfo.GetPathAccessPermission(string(vsrcFile))
-				if accmode == "readonly" {
+				if accmode == fsdef.FsReadOnly {
 					common.SendErrorResponse(w, "This directory is Read Only")
 					return
-				} else if accmode == "denied" {
+				} else if accmode == fsdef.FsDenied {
 					common.SendErrorResponse(w, "Access Denied")
 					return
 				}
@@ -1834,10 +1850,10 @@ func system_fs_handleOpr(w http.ResponseWriter, r *http.Request) {
 
 				//Check if the source file is read only.
 				accmode := userinfo.GetPathAccessPermission(string(vsrcFile))
-				if accmode == "readonly" {
+				if accmode == fsdef.FsReadOnly {
 					common.SendErrorResponse(w, "This source file is Read Only")
 					return
-				} else if accmode == "denied" {
+				} else if accmode == fsdef.FsDenied {
 					common.SendErrorResponse(w, "Access Denied")
 					return
 				}
@@ -1860,18 +1876,20 @@ func system_fs_handleOpr(w http.ResponseWriter, r *http.Request) {
 				//underSameRoot, _ := fs.UnderTheSameRoot(srcAbs, destAbs)
 
 				//Updates 19-10-2020: Added ownership management to file move and copy
-				userinfo.RemoveOwnershipFromFile(rsrcFile)
+				userinfo.RemoveOwnershipFromFile(srcFsh, vsrcFile)
 
 				err = fs.FileMove(srcFsh, rsrcFile, destFsh, rdestFile, existsOpr, true, nil)
 				if err != nil {
 					common.SendErrorResponse(w, err.Error())
 					//Restore the ownership if remove failed
-					userinfo.SetOwnerOfFile(rsrcFile)
+					userinfo.SetOwnerOfFile(srcFsh, vsrcFile)
 					return
 				}
 
 				//Set user to own the new file
-				userinfo.SetOwnerOfFile(filepath.ToSlash(filepath.Clean(rdestFile)) + "/" + filepath.Base(rsrcFile))
+				newfileRpath := filepath.ToSlash(filepath.Clean(rdestFile)) + "/" + filepath.Base(rsrcFile)
+				newfileVpath, _ := destFsh.FileSystemAbstraction.RealPathToVirtualPath(newfileRpath, userinfo.Username)
+				userinfo.SetOwnerOfFile(destFsh, newfileVpath)
 
 				//Remove cache for the original file
 				metadata.RemoveCache(srcFsh, rsrcFile)
@@ -1913,7 +1931,9 @@ func system_fs_handleOpr(w http.ResponseWriter, r *http.Request) {
 				}
 
 				//Set user to own this file
-				userinfo.SetOwnerOfFile(filepath.ToSlash(filepath.Clean(rdestFile)) + "/" + filepath.Base(rsrcFile))
+				newfileRpath := filepath.ToSlash(filepath.Clean(rdestFile)) + "/" + filepath.Base(rsrcFile)
+				newfileVpath, _ := destFsh.FileSystemAbstraction.RealPathToVirtualPath(newfileRpath, userinfo.Username)
+				userinfo.SetOwnerOfFile(destFsh, newfileVpath)
 
 			} else if operation == "delete" {
 				//Delete the file permanently
@@ -1930,10 +1950,10 @@ func system_fs_handleOpr(w http.ResponseWriter, r *http.Request) {
 				}
 
 				//Check if the user own this file
-				isOwner := userinfo.IsOwnerOfFile(rsrcFile)
+				isOwner := userinfo.IsOwnerOfFile(srcFsh, vsrcFile)
 				if isOwner {
 					//This user own this system. Remove this file from his quota
-					userinfo.RemoveOwnershipFromFile(rsrcFile)
+					userinfo.RemoveOwnershipFromFile(srcFsh, vsrcFile)
 				}
 
 				//Check if this file has any cached files. If yes, remove it
@@ -2174,8 +2194,10 @@ func system_fs_listRoot(w http.ResponseWriter, r *http.Request) {
 			IsDir    bool
 		}
 		//List the root media folders under user:/
+		fsh, _ := userinfo.GetFileSystemHandlerFromVirtualPath("user:/")
+		fshAbs := fsh.FileSystemAbstraction
 		filesInUserRoot := []fileObject{}
-		filesInRoot, _ := filepath.Glob(filepath.ToSlash(filepath.Clean(*root_directory)) + "/users/" + username + "/*")
+		filesInRoot, _ := fshAbs.Glob(filepath.ToSlash(filepath.Clean(*root_directory)) + "/users/" + username + "/*")
 		for _, file := range filesInRoot {
 			//Check if this is a hidden file
 			if len(filepath.Base(file)) > 0 && filepath.Base(file)[:1] == "." {
@@ -2183,8 +2205,8 @@ func system_fs_listRoot(w http.ResponseWriter, r *http.Request) {
 			}
 			thisFile := new(fileObject)
 			thisFile.Filename = filepath.Base(file)
-			thisFile.Filepath, _ = userinfo.RealPathToVirtualPath(file)
-			thisFile.IsDir = fs.IsDir(file)
+			thisFile.Filepath, _ = fshAbs.RealPathToVirtualPath(file, userinfo.Username)
+			thisFile.IsDir = fshAbs.IsDir(file)
 			filesInUserRoot = append(filesInUserRoot, *thisFile)
 		}
 		jsonString, _ := json.Marshal(filesInUserRoot)
@@ -2200,17 +2222,11 @@ func system_fs_listRoot(w http.ResponseWriter, r *http.Request) {
 		roots := []*rootObject{}
 		backupRoots := []string{}
 		for _, store := range userinfo.GetAllFileSystemHandler() {
-			if store.Hierarchy == "user" || store.Hierarchy == "public" {
-				//Normal drives
-				var thisDevice = new(rootObject)
-				thisDevice.RootName = store.Name
-				thisDevice.RootPath = store.UUID + ":/"
-				thisDevice.rootID = store.UUID
-				roots = append(roots, thisDevice)
-			} else if store.Hierarchy == "backup" {
-				//Backup drive.
-				backupRoots = append(backupRoots, store.HierarchyConfig.(hybridBackup.BackupTask).ParentUID)
-			}
+			var thisDevice = new(rootObject)
+			thisDevice.RootName = store.Name
+			thisDevice.RootPath = store.UUID + ":/"
+			thisDevice.rootID = store.UUID
+			roots = append(roots, thisDevice)
 		}
 
 		//Update root configs for backup roots
@@ -2355,7 +2371,7 @@ func system_fs_getFileProperties(w http.ResponseWriter, r *http.Request) {
 	}
 
 	//Get file owner
-	owner := userinfo.GetFileOwner(rpath)
+	owner := userinfo.GetFileOwner(fsh, vpath)
 
 	if owner == "" {
 		//Handle special virtual roots
@@ -2814,37 +2830,6 @@ func system_fs_clearVersionHistories() {
 	}
 }
 
-//Translate path from and to virtual and realpath
-func system_fs_handlePathTranslate(w http.ResponseWriter, r *http.Request) {
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	path, err := common.Mv(r, "path", false)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid path given")
-		return
-	}
-	rpath, err := userinfo.VirtualPathToRealPath(path)
-	if err != nil {
-		//Try to convert it to virtualPath
-		vpath, err := userinfo.RealPathToVirtualPath(path)
-		if err != nil {
-			common.SendErrorResponse(w, "Unknown path given")
-		} else {
-			jsonstring, _ := json.Marshal(vpath)
-			common.SendJSONResponse(w, string(jsonstring))
-		}
-	} else {
-		abrpath, _ := filepath.Abs(rpath)
-		jsonstring, _ := json.Marshal([]string{rpath, filepath.ToSlash(abrpath)})
-		common.SendJSONResponse(w, string(jsonstring))
-	}
-
-}
-
 //Handle cache rendering with websocket pipeline
 func system_fs_handleCacheRender(w http.ResponseWriter, r *http.Request) {
 	userinfo, _ := userHandler.GetUserInfoFromRequest(w, r)
@@ -2995,7 +2980,10 @@ func system_fs_handleFilePermission(w http.ResponseWriter, r *http.Request) {
 		common.SendErrorResponse(w, "User not logged in")
 		return
 	}
-	rpath, err := userinfo.VirtualPathToRealPath(file)
+
+	fsh, subpath, err := GetFSHandlerSubpathFromVpath(file)
+	fshAbs := fsh.FileSystemAbstraction
+	rpath, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
 	if err != nil {
 		common.SendErrorResponse(w, err.Error())
 		return
@@ -3005,13 +2993,13 @@ func system_fs_handleFilePermission(w http.ResponseWriter, r *http.Request) {
 		//Read the file mode
 
 		//Check if the file exists
-		if !fs.FileExists(rpath) {
+		if !fshAbs.FileExists(rpath) {
 			common.SendErrorResponse(w, "File not exists!")
 			return
 		}
 
 		//Read the file permission
-		filePermission, err := fsp.GetFilePermissions(rpath)
+		filePermission, err := fsp.GetFilePermissions(fsh, rpath)
 		if err != nil {
 			common.SendErrorResponse(w, err.Error())
 			return
@@ -3056,7 +3044,7 @@ func system_fs_handleFilePermission(w http.ResponseWriter, r *http.Request) {
 		//Be noted that if the system is not running in sudo mode,
 		//File permission change might not works.
 
-		err := fsp.SetFilePermisson(rpath, newMode)
+		err := fsp.SetFilePermisson(fsh, rpath, newMode)
 		if err != nil {
 			common.SendErrorResponse(w, err.Error())
 			return

+ 0 - 0
mod/disk/hybridBackup/basicBackup.go → legacy/_hybridBackup/basicBackup.go


+ 0 - 0
mod/disk/hybridBackup/compareRoots.go → legacy/_hybridBackup/compareRoots.go


+ 0 - 0
mod/disk/hybridBackup/doc.txt → legacy/_hybridBackup/doc.txt


+ 0 - 0
mod/disk/hybridBackup/fastwalk.go → legacy/_hybridBackup/fastwalk.go


+ 0 - 0
mod/disk/hybridBackup/fileUtil.go → legacy/_hybridBackup/fileUtil.go


+ 0 - 0
mod/disk/hybridBackup/hybridBackup.go → legacy/_hybridBackup/hybridBackup.go


+ 0 - 0
mod/disk/hybridBackup/linker.go → legacy/_hybridBackup/linker.go


+ 0 - 0
mod/disk/hybridBackup/snaoshotOpr.go → legacy/_hybridBackup/snaoshotOpr.go


+ 0 - 0
mod/disk/hybridBackup/versionBackup.go → legacy/_hybridBackup/versionBackup.go


+ 5 - 5
mediaServer.go

@@ -184,7 +184,7 @@ func serverMedia(w http.ResponseWriter, r *http.Request) {
 
 		w.Header().Set("Content-Disposition", "attachment; filename=\""+filename+"\"")
 		w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
-		if targetFsh.RequireBuffer {
+		if targetFsh.RequireBuffer || !filesystem.FileExists(realFilepath) {
 			//Stream it directly from remote
 			w.Header().Set("Content-Length", strconv.Itoa(int(targetFshAbs.GetFileSize(realFilepath))))
 			remoteStream, err := targetFshAbs.ReadStream(realFilepath)
@@ -194,13 +194,12 @@ func serverMedia(w http.ResponseWriter, r *http.Request) {
 			}
 			io.Copy(w, remoteStream)
 			remoteStream.Close()
-			return
 		} else {
 			http.ServeFile(w, r, escapedRealFilepath)
 		}
 
 	} else {
-		if targetFsh.RequireBuffer {
+		if targetFsh.RequireBuffer || !filesystem.FileExists(realFilepath) {
 			w.Header().Set("Content-Length", strconv.Itoa(int(targetFshAbs.GetFileSize(realFilepath))))
 			remoteStream, err := targetFshAbs.ReadStream(realFilepath)
 			if err != nil {
@@ -209,9 +208,10 @@ func serverMedia(w http.ResponseWriter, r *http.Request) {
 			}
 			io.Copy(w, remoteStream)
 			remoteStream.Close()
-			return
+		} else {
+			http.ServeFile(w, r, realFilepath)
 		}
-		http.ServeFile(w, r, realFilepath)
+
 	}
 
 }

+ 5 - 5
mod/agi/agi.file.go

@@ -71,10 +71,10 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 		//Check if file already exists.
 		if fsh.FileSystemAbstraction.FileExists(rpath) {
 			//Check if this user own this file
-			isOwner := u.IsOwnerOfFile(rpath)
+			isOwner := u.IsOwnerOfFile(fsh, vpath)
 			if isOwner {
 				//This user own this system. Remove this file from his quota
-				u.RemoveOwnershipFromFile(rpath)
+				u.RemoveOwnershipFromFile(fsh, vpath)
 			}
 		}
 
@@ -87,7 +87,7 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 		}
 
 		//Add the filesize to user quota
-		u.SetOwnerOfFile(rpath)
+		u.SetOwnerOfFile(fsh, vpath)
 
 		reply, _ := vm.ToValue(true)
 		return reply
@@ -117,10 +117,10 @@ func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
 		//Check if file already exists.
 		if fsh.FileSystemAbstraction.FileExists(rpath) {
 			//Check if this user own this file
-			isOwner := u.IsOwnerOfFile(rpath)
+			isOwner := u.IsOwnerOfFile(fsh, vpath)
 			if isOwner {
 				//This user own this system. Remove this file from his quota
-				u.RemoveOwnershipFromFile(rpath)
+				u.RemoveOwnershipFromFile(fsh, vpath)
 			}
 		} else {
 			g.raiseError(errors.New("File not exists"))

+ 3 - 9
mod/agi/agi.http.go

@@ -5,12 +5,10 @@ import (
 	"encoding/base64"
 	"encoding/json"
 	"errors"
-	"io"
 	"io/ioutil"
 	"log"
 	"net/http"
 	"net/url"
-	"os"
 	"path/filepath"
 
 	"github.com/robertkrimen/otto"
@@ -162,12 +160,12 @@ func (g *Gateway) injectHTTPFunctions(vm *otto.Otto, u *user.User) {
 		}
 
 		//Convert the vpath to realpath. Check if it exists
-		rpath, err := u.VirtualPathToRealPath(vpath)
+		fsh, rpath, err := virtualPathToRealPath(vpath, u)
 		if err != nil {
 			return otto.FalseValue()
 		}
 
-		if !fileExists(rpath) || !IsDir(rpath) {
+		if !fsh.FileSystemAbstraction.FileExists(rpath) || !fsh.FileSystemAbstraction.IsDir(rpath) {
 			g.raiseError(errors.New(vpath + " is a file not a directory."))
 			return otto.FalseValue()
 		}
@@ -182,14 +180,10 @@ func (g *Gateway) injectHTTPFunctions(vm *otto.Otto, u *user.User) {
 		defer resp.Body.Close()
 
 		// Create the file
-		out, err := os.Create(downloadDest)
+		err = fsh.FileSystemAbstraction.WriteStream(downloadDest, resp.Body, 0775)
 		if err != nil {
 			return otto.FalseValue()
 		}
-		defer out.Close()
-
-		// Write the body to file
-		_, err = io.Copy(out, resp.Body)
 		return otto.TrueValue()
 	})
 

+ 6 - 7
mod/disk/diskcapacity/dftool/dftool.go

@@ -12,11 +12,10 @@ import (
 )
 
 type Capacity struct {
-	PhysicalDevice    string //The ID of the physical device, like C:/ or /dev/sda1
-	MountingHierarchy string //The Mounting Hierarchy of the vroot
-	Used              int64  //Used capacity in bytes
-	Avilable          int64  //Avilable capacity in bytes
-	Total             int64  //Total capacity in bytes
+	PhysicalDevice string //The ID of the physical device, like C:/ or /dev/sda1
+	Used           int64  //Used capacity in bytes
+	Available      int64  //Avilable capacity in bytes
+	Total          int64  //Total capacity in bytes
 }
 
 func GetCapacityInfoFromPath(realpath string) (*Capacity, error) {
@@ -39,7 +38,7 @@ func GetCapacityInfoFromPath(realpath string) (*Capacity, error) {
 				return &Capacity{
 					PhysicalDevice: ldi.Device,
 					Used:           ldi.Used,
-					Avilable:       ldi.Available,
+					Available:      ldi.Available,
 					Total:          ldi.Volume,
 				}, nil
 			}
@@ -88,7 +87,7 @@ func GetCapacityInfoFromPath(realpath string) (*Capacity, error) {
 		return &Capacity{
 			PhysicalDevice: diskInfoSlice[0],
 			Used:           used * 1024,
-			Avilable:       availbe * 1024,
+			Available:      availbe * 1024,
 			Total:          total * 1024,
 		}, nil
 	}

+ 42 - 3
mod/disk/diskcapacity/diskcapacity.go

@@ -7,6 +7,7 @@ import (
 
 	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/disk/diskcapacity/dftool"
+	"imuslab.com/arozos/mod/filesystem"
 	"imuslab.com/arozos/mod/user"
 )
 
@@ -22,6 +23,15 @@ type Resolver struct {
 	UserHandler *user.UserHandler
 }
 
+type CapacityInfo struct {
+	PhysicalDevice    string
+	FileSystemType    string
+	MountingHierarchy string
+	Used              int64
+	Available         int64
+	Total             int64
+}
+
 //Create a new Capacity Resolver with the given user handler
 func NewCapacityResolver(u *user.UserHandler) *Resolver {
 	return &Resolver{
@@ -64,19 +74,48 @@ func (cr *Resolver) HandleCapacityResolving(w http.ResponseWriter, r *http.Reque
 
 }
 
-func (cr *Resolver) ResolveCapacityInfo(username string, vpath string) (*dftool.Capacity, error) {
+func (cr *Resolver) ResolveCapacityInfo(username string, vpath string) (*CapacityInfo, error) {
 	//Resolve the vpath for this user
 	userinfo, err := cr.UserHandler.GetUserInfoFromUsername(username)
 	if err != nil {
 		return nil, err
 	}
 
-	realpath, err := userinfo.VirtualPathToRealPath(vpath)
+	fsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(vpath)
+	if err != nil {
+		return nil, err
+	}
+
+	realpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(vpath, username)
 	if err != nil {
 		return nil, err
 	}
 
 	realpath = filepath.ToSlash(filepath.Clean(realpath))
 
-	return dftool.GetCapacityInfoFromPath(realpath)
+	if filesystem.FileExists(realpath) && !fsh.RequireBuffer {
+		//This is a local disk
+		capinfo, err := dftool.GetCapacityInfoFromPath(realpath)
+		if err != nil {
+			return nil, err
+		}
+		return &CapacityInfo{
+			PhysicalDevice:    capinfo.PhysicalDevice,
+			FileSystemType:    fsh.Filesystem,
+			MountingHierarchy: fsh.Hierarchy,
+			Used:              capinfo.Used,
+			Available:         capinfo.Available,
+			Total:             capinfo.Total,
+		}, nil
+	} else {
+		//This is a remote disk
+		return &CapacityInfo{
+			PhysicalDevice:    fsh.Path,
+			FileSystemType:    fsh.Filesystem,
+			MountingHierarchy: fsh.Hierarchy,
+			Used:              0,
+			Available:         0,
+			Total:             0,
+		}, nil
+	}
 }

+ 8 - 4
mod/disk/sortfile/sortfile.go

@@ -9,6 +9,7 @@ import (
 	"sort"
 	"strconv"
 
+	"imuslab.com/arozos/mod/filesystem"
 	user "imuslab.com/arozos/mod/user"
 )
 
@@ -47,14 +48,16 @@ func (s *LargeFileScanner) HandleLargeFileList(w http.ResponseWriter, r *http.Re
 	type FileObject struct {
 		Filename string
 		Filepath string
-		realpath string
 		Size     int64
 		IsOwner  bool
+
+		realpath string
+		thisfsh  *filesystem.FileSystemHandler
 	}
 	//Walk all filesystem handlers and buffer all files and their sizes
 	fileList := []*FileObject{}
 	for _, fsh := range fsHandlers {
-		filepath.Walk(fsh.Path, func(path string, info os.FileInfo, err error) error {
+		fsh.FileSystemAbstraction.Walk(fsh.Path, func(path string, info os.FileInfo, err error) error {
 			if info == nil || err != nil {
 				//Disk IO Error
 				return errors.New("Disk IO Error: " + err.Error())
@@ -66,11 +69,12 @@ func (s *LargeFileScanner) HandleLargeFileList(w http.ResponseWriter, r *http.Re
 
 			//Push the current file into the filelist
 			if info.Size() > 0 {
-				vpath, _ := userinfo.RealPathToVirtualPath(path)
+				vpath, _ := fsh.FileSystemAbstraction.RealPathToVirtualPath(path, userinfo.Username)
 				fileList = append(fileList, &FileObject{
 					Filename: filepath.Base(path),
 					Filepath: vpath,
 					realpath: path,
+					thisfsh:  fsh,
 					Size:     info.Size(),
 					IsOwner:  false,
 				})
@@ -99,7 +103,7 @@ func (s *LargeFileScanner) HandleLargeFileList(w http.ResponseWriter, r *http.Re
 
 	//Only check ownership of those requested
 	for _, file := range fileList[:limitInt] {
-		if userinfo.IsOwnerOfFile(file.realpath) {
+		if userinfo.IsOwnerOfFile(file.thisfsh, file.Filepath) {
 			file.IsOwner = true
 		} else {
 			file.IsOwner = false

+ 22 - 22
mod/filesystem/abstractions/emptyfs/emptyfs.go

@@ -6,7 +6,7 @@ import (
 	"path/filepath"
 	"time"
 
-	"imuslab.com/arozos/mod/filesystem/fserror"
+	"imuslab.com/arozos/mod/filesystem/fsdef"
 )
 
 /*
@@ -24,43 +24,43 @@ func NewEmptyFileSystemAbstraction() EmptyFileSystemAbstraction {
 }
 
 func (l EmptyFileSystemAbstraction) Chmod(filename string, mode os.FileMode) error {
-	return fserror.ErrNullOperation
+	return fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) Chown(filename string, uid int, gid int) error {
-	return fserror.ErrNullOperation
+	return fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) Chtimes(filename string, atime time.Time, mtime time.Time) error {
-	return fserror.ErrNullOperation
+	return fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) Create(filename string) (*os.File, error) {
-	return nil, fserror.ErrNullOperation
+	return nil, fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) Mkdir(filename string, mode os.FileMode) error {
-	return fserror.ErrNullOperation
+	return fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) MkdirAll(filename string, mode os.FileMode) error {
-	return fserror.ErrNullOperation
+	return fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) Name() string {
 	return ""
 }
 func (l EmptyFileSystemAbstraction) Open(filename string) (*os.File, error) {
-	return nil, fserror.ErrNullOperation
+	return nil, fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) OpenFile(filename string, flag int, perm os.FileMode) (*os.File, error) {
-	return nil, fserror.ErrNullOperation
+	return nil, fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) Remove(filename string) error {
-	return fserror.ErrNullOperation
+	return fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) RemoveAll(path string) error {
-	return fserror.ErrNullOperation
+	return fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) Rename(oldname, newname string) error {
-	return fserror.ErrNullOperation
+	return fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) Stat(filename string) (os.FileInfo, error) {
-	return nil, fserror.ErrNullOperation
+	return nil, fsdef.ErrNullOperation
 }
 
 /*
@@ -68,11 +68,11 @@ func (l EmptyFileSystemAbstraction) Stat(filename string) (os.FileInfo, error) {
 */
 
 func (l EmptyFileSystemAbstraction) VirtualPathToRealPath(subpath string, username string) (string, error) {
-	return "", fserror.ErrVpathResolveFailed
+	return "", fsdef.ErrVpathResolveFailed
 }
 
 func (l EmptyFileSystemAbstraction) RealPathToVirtualPath(fullpath string, username string) (string, error) {
-	return "", fserror.ErrRpathResolveFailed
+	return "", fsdef.ErrRpathResolveFailed
 }
 
 func (l EmptyFileSystemAbstraction) FileExists(realpath string) bool {
@@ -84,7 +84,7 @@ func (l EmptyFileSystemAbstraction) IsDir(realpath string) bool {
 }
 
 func (l EmptyFileSystemAbstraction) Glob(realpathWildcard string) ([]string, error) {
-	return []string{}, fserror.ErrNullOperation
+	return []string{}, fsdef.ErrNullOperation
 }
 
 func (l EmptyFileSystemAbstraction) GetFileSize(realpath string) int64 {
@@ -92,22 +92,22 @@ func (l EmptyFileSystemAbstraction) GetFileSize(realpath string) int64 {
 }
 
 func (l EmptyFileSystemAbstraction) GetModTime(realpath string) (int64, error) {
-	return 0, fserror.ErrOperationNotSupported
+	return 0, fsdef.ErrOperationNotSupported
 }
 
 func (l EmptyFileSystemAbstraction) WriteFile(filename string, content []byte, mode os.FileMode) error {
-	return fserror.ErrNullOperation
+	return fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) ReadFile(filename string) ([]byte, error) {
-	return []byte(""), fserror.ErrOperationNotSupported
+	return []byte(""), fsdef.ErrOperationNotSupported
 }
 func (l EmptyFileSystemAbstraction) WriteStream(filename string, stream io.Reader, mode os.FileMode) error {
-	return fserror.ErrNullOperation
+	return fsdef.ErrNullOperation
 }
 func (l EmptyFileSystemAbstraction) ReadStream(filename string) (io.ReadCloser, error) {
-	return nil, fserror.ErrOperationNotSupported
+	return nil, fsdef.ErrOperationNotSupported
 }
 
 func (l EmptyFileSystemAbstraction) Walk(root string, walkFn filepath.WalkFunc) error {
-	return fserror.ErrOperationNotSupported
+	return fsdef.ErrOperationNotSupported
 }

+ 3 - 3
mod/filesystem/abstractions/localfs/localfs.go

@@ -8,7 +8,7 @@ import (
 	"time"
 
 	"imuslab.com/arozos/mod/common"
-	"imuslab.com/arozos/mod/filesystem/fserror"
+	"imuslab.com/arozos/mod/filesystem/fsdef"
 )
 
 /*
@@ -90,7 +90,7 @@ func (l LocalFileSystemAbstraction) VirtualPathToRealPath(subpath string, userna
 	} else if l.Hierarchy == "public" {
 		return filepath.ToSlash(filepath.Join(l.Rootpath, subpath)), nil
 	}
-	return "", fserror.ErrVpathResolveFailed
+	return "", fsdef.ErrVpathResolveFailed
 }
 
 func (l LocalFileSystemAbstraction) RealPathToVirtualPath(fullpath string, username string) (string, error) {
@@ -149,7 +149,7 @@ func (l LocalFileSystemAbstraction) RealPathToVirtualPath(fullpath string, usern
 	*/
 	fullpath = filepath.ToSlash(fullpath)
 	if strings.HasPrefix(fullpath, l.UUID+":") && !common.FileExists(fullpath) {
-		return "", fserror.ErrRpathResolveFailed
+		return "", fsdef.ErrRpathResolveFailed
 	}
 	prefix := filepath.ToSlash(filepath.Join(l.Rootpath, "users", username))
 	if l.Hierarchy == "public" {

+ 4 - 0
mod/filesystem/abstractions/webdavfs/webdavfs.go

@@ -128,6 +128,10 @@ func (e WebDAVFileSystem) VirtualPathToRealPath(subpath string, username string)
 
 }
 func (e WebDAVFileSystem) RealPathToVirtualPath(rpath string, username string) (string, error) {
+	rpath = filterFilepath(filepath.ToSlash(filepath.Clean(rpath)))
+	if e.Hierarchy == "user" && strings.HasPrefix(rpath, "/users/"+username) {
+		rpath = strings.TrimPrefix(rpath, "/users/"+username)
+	}
 	return e.UUID + ":" + filepath.ToSlash(rpath), nil
 }
 func (e WebDAVFileSystem) FileExists(filename string) bool {

+ 5 - 3
mod/filesystem/config.go

@@ -4,6 +4,8 @@ import (
 	"encoding/json"
 	"errors"
 	"strings"
+
+	"imuslab.com/arozos/mod/filesystem/fsdef"
 )
 
 //FileSystem configuration. Append more lines if required.
@@ -49,12 +51,12 @@ func ValidateOption(options *FileSystemOption) error {
 		return errors.New("This File System Handler UUID is reserved by the system")
 	}
 
-	if !fileExists(options.Path) {
+	if !FileExists(options.Path) {
 		return errors.New("Path not exists, given: " + options.Path)
 	}
 
 	//Check if access mode is supported
-	if !inSlice([]string{"readonly", "readwrite"}, options.Access) {
+	if !inSlice([]string{fsdef.FsReadOnly, fsdef.FsReadWrite}, options.Access) {
 		return errors.New("Not supported access mode: " + options.Access)
 	}
 
@@ -69,7 +71,7 @@ func ValidateOption(options *FileSystemOption) error {
 	}
 
 	//Check if mount point exists
-	if options.Mountpt != "" && !fileExists(options.Mountpt) {
+	if options.Mountpt != "" && !FileExists(options.Mountpt) {
 		return errors.New("Mount point not exists: " + options.Mountpt)
 	}
 

+ 1 - 1
mod/filesystem/fileOpr.go

@@ -726,7 +726,7 @@ func BufferedLargeFileCopy(src string, dst string, BUFFERSIZE int64) error {
 }
 
 func IsDir(path string) bool {
-	if fileExists(path) == false {
+	if FileExists(path) == false {
 		return false
 	}
 	fi, err := os.Stat(path)

+ 47 - 82
mod/filesystem/filesystem.go

@@ -11,6 +11,8 @@ package filesystem
 */
 
 import (
+	"crypto/md5"
+	"encoding/hex"
 	"errors"
 	"io"
 	"log"
@@ -20,9 +22,10 @@ import (
 	"time"
 
 	db "imuslab.com/arozos/mod/database"
-	"imuslab.com/arozos/mod/disk/hybridBackup"
+	//"imuslab.com/arozos/mod/disk/hybridBackup"
 	"imuslab.com/arozos/mod/filesystem/abstractions/localfs"
 	"imuslab.com/arozos/mod/filesystem/abstractions/webdavfs"
+	"imuslab.com/arozos/mod/filesystem/fsdef"
 )
 
 //Options for creating new file system handler
@@ -130,7 +133,7 @@ func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
 		}
 
 		//Check if the path exists
-		if !fileExists(option.Path) {
+		if !FileExists(option.Path) {
 			return &FileSystemHandler{}, errors.New("Mount point not exists!")
 		}
 
@@ -144,58 +147,29 @@ func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
 		var fsdb *db.Database = nil
 		dbp, err := db.NewDatabase(filepath.ToSlash(filepath.Join(filepath.Clean(option.Path), "aofs.db")), false)
 		if err != nil {
-			if option.Access != "readonly" {
+			if option.Access != fsdef.FsReadOnly {
 				log.Println("[Filesystem] Invalid config: Trying to mount a read only path as read-write mount point. Changing " + option.Name + " mount point to READONLY.")
-				option.Access = "readonly"
+				option.Access = fsdef.FsReadOnly
 			}
 		} else {
 			fsdb = dbp
 		}
 		rootpath := filepath.ToSlash(filepath.Clean(option.Path)) + "/"
-		if option.Hierarchy == "backup" {
-			//Backup disk. Create an Hierarchy Config for this drive
-			hsConfig := hybridBackup.BackupTask{
-				CycleCounter:      0,
-				LastCycleTime:     0,
-				DiskUID:           option.Uuid,
-				DiskPath:          option.Path,
-				ParentUID:         option.Parentuid,
-				Mode:              option.BackupMode,
-				DeleteFileMarkers: map[string]int64{},
-				PanicStopped:      false,
-			}
-			return &FileSystemHandler{
-				Name:                  option.Name,
-				UUID:                  option.Uuid,
-				Path:                  rootpath,
-				ReadOnly:              option.Access == "readonly",
-				RequireBuffer:         false,
-				Parentuid:             option.Parentuid,
-				Hierarchy:             option.Hierarchy,
-				HierarchyConfig:       hsConfig,
-				InitiationTime:        time.Now().Unix(),
-				FilesystemDatabase:    fsdb,
-				FileSystemAbstraction: localfs.NewLocalFileSystemAbstraction(option.Uuid, rootpath, option.Hierarchy, option.Access == "readonly"),
-				Filesystem:            fstype,
-				Closed:                false,
-			}, nil
-		} else {
-			return &FileSystemHandler{
-				Name:                  option.Name,
-				UUID:                  option.Uuid,
-				Path:                  filepath.ToSlash(filepath.Clean(option.Path)) + "/",
-				ReadOnly:              option.Access == "readonly",
-				RequireBuffer:         false,
-				Parentuid:             option.Parentuid,
-				Hierarchy:             option.Hierarchy,
-				HierarchyConfig:       DefaultEmptyHierarchySpecificConfig,
-				InitiationTime:        time.Now().Unix(),
-				FilesystemDatabase:    fsdb,
-				FileSystemAbstraction: localfs.NewLocalFileSystemAbstraction(option.Uuid, rootpath, option.Hierarchy, option.Access == "readonly"),
-				Filesystem:            fstype,
-				Closed:                false,
-			}, nil
-		}
+		return &FileSystemHandler{
+			Name:                  option.Name,
+			UUID:                  option.Uuid,
+			Path:                  filepath.ToSlash(filepath.Clean(option.Path)) + "/",
+			ReadOnly:              option.Access == fsdef.FsReadOnly,
+			RequireBuffer:         false,
+			Parentuid:             option.Parentuid,
+			Hierarchy:             option.Hierarchy,
+			HierarchyConfig:       DefaultEmptyHierarchySpecificConfig,
+			InitiationTime:        time.Now().Unix(),
+			FilesystemDatabase:    fsdb,
+			FileSystemAbstraction: localfs.NewLocalFileSystemAbstraction(option.Uuid, rootpath, option.Hierarchy, option.Access == fsdef.FsReadOnly),
+			Filesystem:            fstype,
+			Closed:                false,
+		}, nil
 
 	} else if fstype == "webdav" {
 		//WebDAV. Create an object and mount it
@@ -210,8 +184,8 @@ func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error) {
 		return &FileSystemHandler{
 			Name:                  option.Name,
 			UUID:                  option.Uuid,
-			Path:                  "",
-			ReadOnly:              option.Access == "readonly",
+			Path:                  option.Path,
+			ReadOnly:              option.Access == fsdef.FsReadOnly,
 			RequireBuffer:         true,
 			Parentuid:             option.Parentuid,
 			Hierarchy:             option.Hierarchy,
@@ -253,6 +227,21 @@ func (fsh *FileSystemHandler) IsRootOf(vpath string) bool {
 	return strings.HasPrefix(vpath, fsh.UUID+":")
 }
 
+func (fsh *FileSystemHandler) GetUniquePathHash(vpath string, username string) string {
+	fshAbs := fsh.FileSystemAbstraction
+	rpath := ""
+	if strings.Contains(vpath, ":/") {
+		rpath, _ = fshAbs.VirtualPathToRealPath(vpath, username)
+		rpath = filepath.ToSlash(rpath)
+	} else {
+		//Passed in realpath as vpath.
+		rpath = vpath
+	}
+
+	hash := md5.Sum([]byte(fsh.UUID + "_" + rpath))
+	return hex.EncodeToString(hash[:])
+}
+
 func (fsh *FileSystemHandler) GetDirctorySizeFromRealPath(rpath string, includeHidden bool) (int64, int) {
 	var size int64 = 0
 	var fileCount int = 0
@@ -294,40 +283,27 @@ func (fsh *FileSystemHandler) GetDirctorySizeFromVpath(vpath string, username st
 */
 
 //Create a file ownership record
-func (fsh *FileSystemHandler) CreateFileRecord(realpath string, owner string) error {
+func (fsh *FileSystemHandler) CreateFileRecord(rpath string, owner string) error {
 	if fsh.FilesystemDatabase == nil {
 		//Not supported file system type
 		return errors.New("Not supported filesystem type")
 	}
-	rpabs, _ := filepath.Abs(realpath)
-	fsrabs, _ := filepath.Abs(fsh.Path)
-	reldir, err := filepath.Rel(fsrabs, rpabs)
-	if err != nil {
-		return err
-
-	}
 	fsh.FilesystemDatabase.NewTable("owner")
-	fsh.FilesystemDatabase.Write("owner", "owner/"+reldir, owner)
+	fsh.FilesystemDatabase.Write("owner", "owner/"+rpath, owner)
 	return nil
 }
 
 //Read the owner of a file
-func (fsh *FileSystemHandler) GetFileRecord(realpath string) (string, error) {
+func (fsh *FileSystemHandler) GetFileRecord(rpath string) (string, error) {
 	if fsh.FilesystemDatabase == nil {
 		//Not supported file system type
 		return "", errors.New("Not supported filesystem type")
 	}
 
-	rpabs, _ := filepath.Abs(realpath)
-	fsrabs, _ := filepath.Abs(fsh.Path)
-	reldir, err := filepath.Rel(fsrabs, rpabs)
-	if err != nil {
-		return "", err
-	}
 	fsh.FilesystemDatabase.NewTable("owner")
-	if fsh.FilesystemDatabase.KeyExists("owner", "owner/"+reldir) {
+	if fsh.FilesystemDatabase.KeyExists("owner", "owner/"+rpath) {
 		owner := ""
-		fsh.FilesystemDatabase.Read("owner", "owner/"+reldir, &owner)
+		fsh.FilesystemDatabase.Read("owner", "owner/"+rpath, &owner)
 		return owner, nil
 	} else {
 		return "", errors.New("Owner not exists")
@@ -335,21 +311,15 @@ func (fsh *FileSystemHandler) GetFileRecord(realpath string) (string, error) {
 }
 
 //Delete a file ownership record
-func (fsh *FileSystemHandler) DeleteFileRecord(realpath string) error {
+func (fsh *FileSystemHandler) DeleteFileRecord(rpath string) error {
 	if fsh.FilesystemDatabase == nil {
 		//Not supported file system type
 		return errors.New("Not supported filesystem type")
 	}
 
-	rpabs, _ := filepath.Abs(realpath)
-	fsrabs, _ := filepath.Abs(fsh.Path)
-	reldir, err := filepath.Rel(fsrabs, rpabs)
-	if err != nil {
-		return err
-	}
 	fsh.FilesystemDatabase.NewTable("owner")
-	if fsh.FilesystemDatabase.KeyExists("owner", "owner/"+reldir) {
-		fsh.FilesystemDatabase.Delete("owner", "owner/"+reldir)
+	if fsh.FilesystemDatabase.KeyExists("owner", "owner/"+rpath) {
+		fsh.FilesystemDatabase.Delete("owner", "owner/"+rpath)
 	}
 
 	return nil
@@ -375,11 +345,6 @@ func inSlice(slice []string, val string) bool {
 }
 
 func FileExists(filename string) bool {
-	return fileExists(filename)
-}
-
-//Check if file exists
-func fileExists(filename string) bool {
 	_, err := os.Stat(filename)
 	if os.IsNotExist(err) {
 		return false

+ 13 - 2
mod/filesystem/fserror/fserror.go → mod/filesystem/fsdef/fsdef.go

@@ -1,7 +1,7 @@
-package fserror
+package fsdef
 
 /*
-	fserror.go
+	fsdef.go
 
 	This package handle error related to file systems.
 	See comments below for usage.
@@ -9,6 +9,17 @@ package fserror
 import "errors"
 
 var (
+	/*
+		READ WRITE PERMISSIONS
+	*/
+	FsReadOnly  = "readonly"
+	FsWriteOnly = "writeonly"
+	FsReadWrite = "readwrite"
+	FsDenied    = "denied"
+
+	/*
+		ERROR TYPES
+	*/
 	//Redirective Error
 	ErrRedirectParent      = errors.New("Redirect:parent")
 	ErrRedirectCurrentRoot = errors.New("Redirect:root")

+ 52 - 42
mod/filesystem/fspermission/fspermission.go

@@ -6,6 +6,9 @@ import (
 	"log"
 	"os"
 	"strconv"
+
+	"imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/filesystem/fsdef"
 )
 
 /*
@@ -14,8 +17,9 @@ import (
 
 */
 
-func GetFilePermissions(file string) (string, error) {
-	fileStat, err := os.Stat(file)
+func GetFilePermissions(fsh *filesystem.FileSystemHandler, file string) (string, error) {
+	fshAbs := fsh.FileSystemAbstraction
+	fileStat, err := fshAbs.Stat(file)
 	if err != nil {
 		return "", err
 	}
@@ -25,54 +29,60 @@ func GetFilePermissions(file string) (string, error) {
 	return permission, nil
 }
 
-func SetFilePermisson(file string, permissionKey string) error {
-	mode := os.FileMode(0644)
-	if len(permissionKey) != 4 {
-		return errors.New("Invalid File Node")
-	}
-
-	finalMode := 0
-	for i := 0; i < len(permissionKey); i++ {
-		thisInt, err := strconv.Atoi(string(permissionKey[i]))
-		if err != nil {
-			return errors.New("Failed to parse permission key")
+func SetFilePermisson(fsh *filesystem.FileSystemHandler, file string, permissionKey string) error {
+	fshAbs := fsh.FileSystemAbstraction
+	if fshAbs.FileExists(file) && filesystem.FileExists(file) {
+		//This ensure this must be a local file on the system
+		mode := os.FileMode(0644)
+		if len(permissionKey) != 4 {
+			return errors.New("Invalid File Node")
 		}
-		if i == 0 {
-			if thisInt != 0 {
+
+		finalMode := 0
+		for i := 0; i < len(permissionKey); i++ {
+			thisInt, err := strconv.Atoi(string(permissionKey[i]))
+			if err != nil {
 				return errors.New("Failed to parse permission key")
 			}
-		} else if i == 1 {
-			if thisInt > 7 {
-				return errors.New("Failed to parse permission key: Permission value > 7")
-			} else {
-				finalMode = finalMode + thisInt*100
-			}
-		} else if i == 2 {
-			if thisInt > 7 {
-				return errors.New("Failed to parse permission key: Permission value > 7")
-			} else {
-				finalMode = finalMode + thisInt*10
-			}
-		} else if i == 3 {
-			if thisInt > 7 {
-				return errors.New("Failed to parse permission key: Permission value > 7")
-			} else {
-				finalMode = finalMode + thisInt
+			if i == 0 {
+				if thisInt != 0 {
+					return errors.New("Failed to parse permission key")
+				}
+			} else if i == 1 {
+				if thisInt > 7 {
+					return errors.New("Failed to parse permission key: Permission value > 7")
+				} else {
+					finalMode = finalMode + thisInt*100
+				}
+			} else if i == 2 {
+				if thisInt > 7 {
+					return errors.New("Failed to parse permission key: Permission value > 7")
+				} else {
+					finalMode = finalMode + thisInt*10
+				}
+			} else if i == 3 {
+				if thisInt > 7 {
+					return errors.New("Failed to parse permission key: Permission value > 7")
+				} else {
+					finalMode = finalMode + thisInt
+				}
 			}
 		}
-	}
 
-	//Convert the value into a file mode
-	log.Println("Updating " + file + " permission to " + strconv.Itoa(finalMode))
+		//Convert the value into a file mode
+		log.Println("Updating " + file + " permission to " + strconv.Itoa(finalMode))
 
-	//Magic way to convert dec to oct
-	output, _ := strconv.ParseInt("0"+strconv.Itoa(finalMode), 8, 64)
-	mode = os.FileMode(output)
+		//Magic way to convert dec to oct
+		output, _ := strconv.ParseInt("0"+strconv.Itoa(finalMode), 8, 64)
+		mode = os.FileMode(output)
 
-	//Set its mode
-	err := os.Chmod(file, mode)
-	if err != nil {
-		return err
+		//Set its mode
+		err := os.Chmod(file, mode)
+		if err != nil {
+			return err
+		}
+	} else {
+		return fsdef.ErrOperationNotSupported
 	}
 	return nil
 }

+ 2 - 2
mod/filesystem/static.go

@@ -169,7 +169,7 @@ func MountDevice(mountpt string, mountdev string, filesystem string) error {
 		}
 
 		//Check if device exists
-		if !fileExists(mountdev) {
+		if !FileExists(mountdev) {
 			//Device driver not exists.
 			return errors.New("Device not exists: " + mountdev)
 		}
@@ -185,7 +185,7 @@ func MountDevice(mountpt string, mountdev string, filesystem string) error {
 		}
 
 		//Check if the path exists
-		if !fileExists(mountpt) {
+		if !FileExists(mountpt) {
 			//Mounted but path still not found. Skip this device
 			return errors.New("Unable to find " + mountpt)
 		}

+ 0 - 13
mod/info/hardwareinfo/hardwareinfo.go

@@ -66,19 +66,6 @@ func PrintSystemHardwareDebugMessage() {
 }
 
 func (s *Server) GetArOZInfo(w http.ResponseWriter, r *http.Request) {
-
-	/*
-		ArOZInfo := ArOZInfo{
-			BuildVersion: build_version + "." + internal_version,
-			DeviceVendor: deviceVendor,
-			DeviceModel:  deviceModel,
-			VendorIcon:   "../../" + iconVendor,
-			SN:           deviceUUID,
-			HostOS:       runtime.GOOS,
-			CPUArch:      runtime.GOARCH,
-		}
-	*/
-
 	var jsonData []byte
 	jsonData, err := json.Marshal(s.hostInfo)
 	if err != nil {

+ 1 - 0
mod/info/hardwareinfo/sysinfo_freebsd.go

@@ -1,3 +1,4 @@
+//go:build freebsd
 // +build freebsd
 
 package hardwareinfo

+ 5 - 4
mod/share/share.go

@@ -689,14 +689,15 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", contentType)
 				w.Header().Set("Content-Length", strconv.Itoa(int(targetFshAbs.GetFileSize(fileRuntimeAbsPath))))
 
-				if targetFsh.RequireBuffer {
+				if filesystem.FileExists(fileRuntimeAbsPath) {
+					//This file exists in local file system. Serve it directly
+					http.ServeFile(w, r, fileRuntimeAbsPath)
+				} else {
+					//This file is not on local file system. Use streaming
 					f, _ := targetFshAbs.ReadStream(fileRuntimeAbsPath)
 					io.Copy(w, f)
 					f.Close()
-				} else {
-					http.ServeFile(w, r, fileRuntimeAbsPath)
 				}
-
 			} else if directServe {
 				w.Header().Set("Access-Control-Allow-Origin", "*")
 				w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

+ 1 - 14
mod/share/shareEntry/shareEntry.go

@@ -1,8 +1,6 @@
 package shareEntry
 
 import (
-	"crypto/md5"
-	"encoding/hex"
 	"encoding/json"
 	"errors"
 	"path/filepath"
@@ -252,16 +250,5 @@ func (s *ShareEntryTable) ResolveShareOptionFromShareSubpath(subpath string) (*S
 }
 
 func GetPathHash(fsh *filesystem.FileSystemHandler, vpath string, username string) string {
-	fshAbs := fsh.FileSystemAbstraction
-	rpath := ""
-	if strings.Contains(vpath, ":/") {
-		rpath, _ = fshAbs.VirtualPathToRealPath(vpath, username)
-		rpath = filepath.ToSlash(rpath)
-	} else {
-		//Passed in realpath as vpath.
-		rpath = vpath
-	}
-
-	hash := md5.Sum([]byte(fsh.UUID + "_" + rpath))
-	return hex.EncodeToString(hash[:])
+	return fsh.GetUniquePathHash(vpath, username)
 }

+ 155 - 184
mod/storage/ftp/aofs.go

@@ -5,17 +5,15 @@ package ftp
 
 import (
 	"errors"
+	"fmt"
 	"io/ioutil"
-	"log"
 	"os"
 	"path/filepath"
-	"strconv"
 	"strings"
 	"time"
 
 	"github.com/spf13/afero"
-	fs "imuslab.com/arozos/mod/filesystem"
-	"imuslab.com/arozos/mod/filesystem/hidden"
+	"imuslab.com/arozos/mod/filesystem"
 	"imuslab.com/arozos/mod/user"
 )
 
@@ -25,129 +23,151 @@ type aofs struct {
 }
 
 func (a aofs) Create(name string) (afero.File, error) {
-	rewritePath, _, err := a.pathRewrite(name)
-	if err != nil {
-		return nil, err
-	}
-	if !a.checkAllowAccess(rewritePath, "write") {
-		return nil, errors.New("Permission Denied")
-	}
-	//log.Println("Create", rewritePath)
-	fd, err := os.Create(rewritePath)
-	if err != nil {
-		return nil, err
-	}
-	return fd, nil
+	/*
+		rewritePath, _, err := a.pathRewrite(name)
+		if err != nil {
+			return nil, err
+		}
+		if !a.checkAllowAccess(rewritePath, "write") {
+			return nil, errors.New("Permission Denied")
+		}
+		//log.Println("Create", rewritePath)
+		fd, err := os.Create(rewritePath)
+		if err != nil {
+			return nil, err
+		}
+		return fd, nil
+	*/
+	return nil, nil
 }
 
 func (a aofs) Chown(name string, uid, gid int) error {
-	rewritePath, _, err := a.pathRewrite(name)
-	if err != nil {
-		return err
-	}
+	/*
+		rewritePath, _, err := a.pathRewrite(name)
+		if err != nil {
+			return err
+		}
 
-	if !a.checkAllowAccess(rewritePath, "write") {
-		return errors.New("Permission Denied")
-	}
+		if !a.checkAllowAccess(rewritePath, "write") {
+			return errors.New("Permission Denied")
+		}
 
-	return os.Chown(name, uid, gid)
+		return os.Chown(name, uid, gid)
+	*/
+	return nil
 }
 
 func (a aofs) Mkdir(name string, perm os.FileMode) error {
-	rewritePath, _, err := a.pathRewrite(name)
-	if err != nil {
-		return err
-	}
-	if !a.checkAllowAccess(rewritePath, "write") {
-		return errors.New("Permission Denied")
-	}
+	/*
+		rewritePath, _, err := a.pathRewrite(name)
+		if err != nil {
+			return err
+		}
+		if !a.checkAllowAccess(rewritePath, "write") {
+			return errors.New("Permission Denied")
+		}
+
+		os.Mkdir(rewritePath, perm)
 
-	os.Mkdir(rewritePath, perm)
+	*/
 	return nil
 }
 
 func (a aofs) MkdirAll(path string, perm os.FileMode) error {
-	rewritePath, _, err := a.pathRewrite(path)
-	if err != nil {
-		return err
-	}
-	if !a.checkAllowAccess(rewritePath, "write") {
-		return errors.New("Permission Denied")
-	}
+	/*
+		rewritePath, _, err := a.pathRewrite(path)
+		if err != nil {
+			return err
+		}
+		if !a.checkAllowAccess(rewritePath, "write") {
+			return errors.New("Permission Denied")
+		}
 
-	os.MkdirAll(rewritePath, perm)
+		os.MkdirAll(rewritePath, perm)
+		return nil
+	*/
 	return nil
 }
 
 func (a aofs) Open(name string) (afero.File, error) {
-	rewritePath, _, err := a.pathRewrite(name)
-	if err != nil {
-		return nil, err
-	}
-	if !a.checkAllowAccess(rewritePath, "read") {
-		return nil, errors.New("Permission Denied")
-	}
-	//log.Println("Open", name, rewritePath)
-
-	fd, err := os.Open(rewritePath)
-	if err != nil {
-		return nil, err
-	}
+	fmt.Println("FTP OPEN")
+	/*
+		rewritePath, _, err := a.pathRewrite(name)
+		if err != nil {
+			return nil, err
+		}
+		if !a.checkAllowAccess(rewritePath, "read") {
+			return nil, errors.New("Permission Denied")
+		}
+		//log.Println("Open", name, rewritePath)
 
-	return fd, nil
+		fd, err := os.Open(rewritePath)
+		if err != nil {
+			return nil, err
+		}
 
+		return fd, nil
+	*/
+	return nil, nil
 }
 
 func (a aofs) Stat(name string) (os.FileInfo, error) {
-	rewritePath, _, err := a.pathRewrite(name)
-	if err != nil {
-		return nil, err
-	}
-	if !a.checkAllowAccess(rewritePath, "read") {
-		return nil, errors.New("Permission Denied")
-	}
-	//log.Println("Stat", rewritePath)
-	fileStat, err := os.Stat(rewritePath)
-
-	return fileStat, err
-}
-
-func (a aofs) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
-	rewritePath, _, err := a.pathRewrite(name)
-	if err != nil {
-		return nil, err
-	}
-	//log.Println("OpenFile", rewritePath)
-	if !fileExists(rewritePath) {
-		if !a.checkAllowAccess(rewritePath, "write") {
-			return nil, errors.New("Directory is Read Only")
-		}
-
-		//Set ownership of this file to user.
-		//Cannot use SetOwnership due to the filesize of the given file didn't exists yet
-		fsh, _ := a.userinfo.GetFileSystemHandlerFromRealPath(rewritePath)
-		fsh.CreateFileRecord(rewritePath, a.userinfo.Username)
-
-		//Create the upload pending file
-		fd, err := os.Create(rewritePath)
+	fmt.Println("FTP STAT")
+	/*
+		rewritePath, _, err := a.pathRewrite(name)
 		if err != nil {
 			return nil, err
 		}
-		return fd, nil
-	} else {
 		if !a.checkAllowAccess(rewritePath, "read") {
 			return nil, errors.New("Permission Denied")
 		}
-		fd, err := os.Open(rewritePath)
+		//log.Println("Stat", rewritePath)
+		fileStat, err := os.Stat(rewritePath)
+
+		return fileStat, err
+	*/
+	return nil, nil
+}
+
+func (a aofs) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
+	fmt.Println("FTP OPEN FILE")
+	/*
+		rewritePath, _, err := a.pathRewrite(name)
 		if err != nil {
 			return nil, err
 		}
-		return fd, nil
-	}
+		//log.Println("OpenFile", rewritePath)
+		if !fileExists(rewritePath) {
+			if !a.checkAllowAccess(rewritePath, "write") {
+				return nil, errors.New("Directory is Read Only")
+			}
+
+			//Set ownership of this file to user.
+			//Cannot use SetOwnership due to the filesize of the given file didn't exists yet
+			fsh, _ := a.userinfo.GetFileSystemHandlerFromRealPath(rewritePath)
+			fsh.CreateFileRecord(rewritePath, a.userinfo.Username)
+
+			//Create the upload pending file
+			fd, err := os.Create(rewritePath)
+			if err != nil {
+				return nil, err
+			}
+			return fd, nil
+		} else {
+			if !a.checkAllowAccess(rewritePath, "read") {
+				return nil, errors.New("Permission Denied")
+			}
+			fd, err := os.Open(rewritePath)
+			if err != nil {
+				return nil, err
+			}
+			return fd, nil
+		}
+	*/
+	return nil, nil
 }
 
 func (a aofs) AllocateSpace(size int) error {
-	//log.Println("AllocateSpace", size)
 	if a.userinfo.StorageQuota.HaveSpace(int64(size)) {
 		return nil
 	}
@@ -155,65 +175,51 @@ func (a aofs) AllocateSpace(size int) error {
 }
 
 func (a aofs) Remove(name string) error {
-	rewritePath, _, err := a.pathRewrite(name)
-	if err != nil {
-		return err
-	}
-	if !a.checkAllowAccess(rewritePath, "write") {
-		return errors.New("Target is Read Only")
-	}
+	/*
+		rewritePath, _, err := a.pathRewrite(name)
+		if err != nil {
+			return err
+		}
+		if !a.checkAllowAccess(rewritePath, "write") {
+			return errors.New("Target is Read Only")
+		}
 
-	isHiddenFile, _ := hidden.IsHidden(rewritePath, true)
-	if isHiddenFile {
-		//Hidden files, include cache or trash
-		return errors.New("Access denied for hidden files")
-	}
+		isHiddenFile, _ := hidden.IsHidden(rewritePath, true)
+		if isHiddenFile {
+			//Hidden files, include cache or trash
+			return errors.New("Access denied for hidden files")
+		}
 
-	log.Println(a.userinfo.Username + " removed " + rewritePath + " via FTP endpoint")
-	os.MkdirAll(filepath.Dir(rewritePath)+"/.metadata/.trash/", 0755)
-	os.Rename(rewritePath, filepath.Dir(rewritePath)+"/.metadata/.trash/"+filepath.Base(rewritePath)+"."+strconv.Itoa(int(time.Now().Unix())))
+		log.Println(a.userinfo.Username + " removed " + rewritePath + " via FTP endpoint")
+		os.MkdirAll(filepath.Dir(rewritePath)+"/.metadata/.trash/", 0755)
+		os.Rename(rewritePath, filepath.Dir(rewritePath)+"/.metadata/.trash/"+filepath.Base(rewritePath)+"."+strconv.Itoa(int(time.Now().Unix())))
+	*/
 	return nil
 }
 
 func (a aofs) RemoveAll(path string) error {
-	rewritePath, _, err := a.pathRewrite(path)
-	if err != nil {
-		return err
-	}
-	//log.Println("RemoveAll", rewritePath)
-	isHiddenFile, _ := hidden.IsHidden(rewritePath, true)
-	if isHiddenFile {
-		//Hidden files, include cache or trash
-		return errors.New("Target is Read Only")
-	}
-	if !a.checkAllowAccess(rewritePath, "write") {
-		return errors.New("Permission Denied")
-	}
-	os.MkdirAll(filepath.Dir(rewritePath)+"/.metadata/.trash/", 0755)
-	os.Rename(rewritePath, filepath.Dir(rewritePath)+"/.metadata/.trash/"+filepath.Base(rewritePath)+"."+strconv.Itoa(int(time.Now().Unix())))
+	/*
+		rewritePath, _, err := a.pathRewrite(path)
+		if err != nil {
+			return err
+		}
+		//log.Println("RemoveAll", rewritePath)
+		isHiddenFile, _ := hidden.IsHidden(rewritePath, true)
+		if isHiddenFile {
+			//Hidden files, include cache or trash
+			return errors.New("Target is Read Only")
+		}
+		if !a.checkAllowAccess(rewritePath, "write") {
+			return errors.New("Permission Denied")
+		}
+		os.MkdirAll(filepath.Dir(rewritePath)+"/.metadata/.trash/", 0755)
+		os.Rename(rewritePath, filepath.Dir(rewritePath)+"/.metadata/.trash/"+filepath.Base(rewritePath)+"."+strconv.Itoa(int(time.Now().Unix())))
+	*/
 	return nil
 }
 
 func (a aofs) Rename(oldname, newname string) error {
-	oldpath, _, err := a.pathRewrite(oldname)
-	if err != nil {
-		return err
-	}
-	newpath, _, err := a.pathRewrite(newname)
-	if err != nil {
-		return err
-	}
-	if !a.checkAllowAccess(oldpath, "write") {
-		return errors.New("Target is Read Only")
-	}
-	if !a.checkAllowAccess(newpath, "write") {
-		return errors.New("Target is Read Only")
-	}
-	if fileExists(newpath) {
-		return errors.New("File already exists")
-	}
-	os.Rename(oldpath, newpath)
-	//log.Println("Rename", oldpath, newpath)
+
 	return nil
 
 }
@@ -234,7 +240,7 @@ func (a aofs) Chtimes(name string, atime time.Time, mtime time.Time) error {
 
 //arozos adaptive functions
 //This function rewrite the path from ftp representation to real filepath on disk
-func (a aofs) pathRewrite(path string) (string, *fs.FileSystemHandler, error) {
+func (a aofs) pathRewrite(path string) (*filesystem.FileSystemHandler, string, error) {
 	path = filepath.ToSlash(filepath.Clean(path))
 	//log.Println("Original path: ", path)
 	if path == "/" {
@@ -255,10 +261,10 @@ func (a aofs) pathRewrite(path string) (string, *fs.FileSystemHandler, error) {
 
 		//Return the tmpFolder root
 		tmpfs, _ := a.userinfo.GetFileSystemHandlerFromVirtualPath("tmp:/")
-		return a.tmpFolder, tmpfs, nil
+		return tmpfs, a.tmpFolder, nil
 	} else if path == "/README.txt" {
 		tmpfs, _ := a.userinfo.GetFileSystemHandlerFromVirtualPath("tmp:/")
-		return a.tmpFolder + "README.txt", tmpfs, nil
+		return tmpfs, a.tmpFolder + "README.txt", nil
 	} else if len(path) > 0 {
 		//Rewrite the path for any alternative filepath
 		//Get the uuid of the filepath
@@ -274,59 +280,24 @@ func (a aofs) pathRewrite(path string) (string, *fs.FileSystemHandler, error) {
 			if fsh.UUID == fsHandlerUUID {
 				//This is the correct handler
 				if fsh.Hierarchy == "user" {
-					return filepath.ToSlash(filepath.Clean(fsh.Path)) + "/users/" + a.userinfo.Username + "/" + strings.Join(remainingPaths, "/"), fsh, nil
+					return fsh, filepath.ToSlash(filepath.Clean(fsh.Path)) + "/users/" + a.userinfo.Username + "/" + strings.Join(remainingPaths, "/"), nil
 				} else if fsh.Hierarchy == "public" {
-					return filepath.ToSlash(filepath.Clean(fsh.Path)) + "/" + strings.Join(remainingPaths, "/"), fsh, nil
+					return fsh, filepath.ToSlash(filepath.Clean(fsh.Path)) + "/" + strings.Join(remainingPaths, "/"), nil
 				}
 
 			}
 		}
 
 		//fsh not found.
-		return "", nil, errors.New("Path is READ ONLY")
+		return nil, "", errors.New("Path is READ ONLY")
 	} else {
 		//fsh not found.
-		return "", nil, errors.New("Invalid path")
+		return nil, "", errors.New("Invalid path")
 	}
 }
 
 //Check if user has access to the given path, mode can be string {read / write}
-func (a aofs) checkAllowAccess(path string, mode string) bool {
-	//Convert the realpath to virtualpath
-	vpath, err := a.userinfo.RealPathToVirtualPath(path)
-	if err != nil {
-		log.Println("ERROR: " + a.userinfo.Username + " tried to access " + path + " but failed: " + err.Error())
-		return false
-	}
-
-	isHiddenFolder, _ := hidden.IsHidden(vpath, true)
-	if isHiddenFolder {
-		return false
-	}
-
-	if mode == "read" {
-		return a.userinfo.CanRead(vpath)
-	} else if mode == "write" {
-		return a.userinfo.CanWrite(vpath)
-	}
-	log.Println(path, mode)
-	//Unknown path. Return false for security purposes
-	return false
-}
-
-//Helper functs
-func isDir(path string) bool {
-	fileInfo, err := os.Stat(path)
-	if err != nil {
-		return false
-	}
-	return fileInfo.IsDir()
-}
-
-func fileExists(path string) bool {
-	if _, err := os.Stat(path); os.IsNotExist(err) {
-		return false
-	}
+func (a aofs) checkAllowAccess(fsh *filesystem.FileSystemHandler, path string, mode string) bool {
 
 	return true
 }

+ 11 - 42
mod/storage/storage.go

@@ -9,21 +9,19 @@ package storage
 */
 
 import (
-	"log"
 	"os"
 	"strings"
 
-	"imuslab.com/arozos/mod/disk/hybridBackup"
 	"imuslab.com/arozos/mod/filesystem"
 	fs "imuslab.com/arozos/mod/filesystem"
-	"imuslab.com/arozos/mod/filesystem/fserror"
+	"imuslab.com/arozos/mod/filesystem/fsdef"
 )
 
 type StoragePool struct {
-	Owner              string                  //Owner of the storage pool, also act as the resolver's username
-	OtherPermission    string                  //Permissions on other users but not the owner
-	Storages           []*fs.FileSystemHandler //Storage pool accessable by this owner
-	HyperBackupManager *hybridBackup.Manager   //HyperBackup Manager
+	Owner           string                  //Owner of the storage pool, also act as the resolver's username
+	OtherPermission string                  //Permissions on other users but not the owner
+	Storages        []*fs.FileSystemHandler //Storage pool accessable by this owner
+	//HyperBackupManager *hybridBackup.Manager   //HyperBackup Manager
 }
 
 /*
@@ -40,43 +38,17 @@ func init() {
 
 //Create a new StoragePool objects with given uuids
 func NewStoragePool(fsHandlers []*fs.FileSystemHandler, owner string) (*StoragePool, error) {
-	//Create new HypberBackup Manager
-	backupManager := hybridBackup.NewHyperBackupManager()
-
 	//Move all fshandler into the storageHandler
 	storageHandlers := []*fs.FileSystemHandler{}
 	for _, fsHandler := range fsHandlers {
 		//Move the handler pointer to the target
 		storageHandlers = append(storageHandlers, fsHandler)
-
-		if fsHandler.Hierarchy == "backup" {
-			//Backup disk. Build the Hierarchy Config for this drive
-			backupConfig := fsHandler.HierarchyConfig.(hybridBackup.BackupTask)
-
-			//Resolve parent path for backup File System Handler
-			parentExists := false
-			for _, potentialParnet := range fsHandlers {
-				if potentialParnet.UUID == backupConfig.ParentUID {
-					//This is the parent
-					backupConfig.ParentPath = potentialParnet.Path
-					parentExists = true
-				}
-			}
-
-			if parentExists {
-				backupManager.AddTask(&backupConfig)
-			} else {
-				log.Println("*ERROR* Backup disk " + backupConfig.DiskUID + ":/ source disk not found: " + backupConfig.ParentUID + ":/ not exists or it is from other storage pool!")
-			}
-
-		}
 	}
 
 	return &StoragePool{
-		Owner:              owner,
-		OtherPermission:    "readonly",
-		Storages:           storageHandlers,
-		HyperBackupManager: backupManager,
+		Owner:           owner,
+		OtherPermission: fsdef.FsReadOnly,
+		Storages:        storageHandlers,
 	}, nil
 }
 
@@ -93,9 +65,9 @@ func (s *StoragePool) ContainDiskID(diskID string) bool {
 
 //Use to compare two StoragePool permissions leve
 func (s *StoragePool) HasHigherOrEqualPermissionThan(a *StoragePool) bool {
-	if s.OtherPermission == "readonly" && a.OtherPermission == "readwrite" {
+	if s.OtherPermission == fsdef.FsReadOnly && a.OtherPermission == fsdef.FsReadWrite {
 		return false
-	} else if s.OtherPermission == "denied" && a.OtherPermission != "denied" {
+	} else if s.OtherPermission == fsdef.FsDenied && a.OtherPermission != fsdef.FsDenied {
 		return false
 	}
 	return true
@@ -128,14 +100,11 @@ func (s *StoragePool) GetFsHandlerByUUID(uuid string) (*fs.FileSystemHandler, er
 		}
 	}
 
-	return nil, fserror.ErrFSHNotFOund
+	return nil, fsdef.ErrFSHNotFOund
 }
 
 //Close all fsHandler under this storage pool
 func (s *StoragePool) Close() {
-	//Close the running backup tasks
-	s.HyperBackupManager.Close()
-
 	//For each storage pool, close it
 	for _, fsh := range s.Storages {
 		fsh.Close()

+ 9 - 3
mod/time/scheduler/handlers.go

@@ -88,8 +88,13 @@ func (a *Scheduler) HandleAddJob(w http.ResponseWriter, r *http.Request) {
 
 	//Can be empty
 	jobDescription, _ := mv(r, "desc", true)
-
-	realScriptPath, err := userinfo.VirtualPathToRealPath(scriptpath)
+	fsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(scriptpath)
+	if err != nil {
+		sendErrorResponse(w, err.Error())
+		return
+	}
+	fshAbs := fsh.FileSystemAbstraction
+	realScriptPath, err := fshAbs.VirtualPathToRealPath(scriptpath, userinfo.Username)
 	if err != nil {
 		sendErrorResponse(w, err.Error())
 		return
@@ -98,7 +103,7 @@ func (a *Scheduler) HandleAddJob(w http.ResponseWriter, r *http.Request) {
 	//Check if the user has permission to create this script
 	if filepath.Ext(realScriptPath) != ".js" && filepath.Ext(realScriptPath) != ".agi" {
 		//Require admin permission
-		if userinfo.IsAdmin() == false {
+		if !userinfo.IsAdmin() {
 			sendErrorResponse(w, "Admin permission required for scheduling non AGI script")
 			return
 		}
@@ -146,6 +151,7 @@ func (a *Scheduler) HandleAddJob(w http.ResponseWriter, r *http.Request) {
 		ExecutionInterval: int64(interval),
 		BaseTime:          baseUnixTime,
 		ScriptFile:        realScriptPath,
+		FshID:             fsh.UUID,
 	}
 
 	//Write current job lists to file

+ 8 - 7
mod/time/scheduler/scheduler.go

@@ -25,13 +25,14 @@ import (
 */
 
 type Job struct {
-	Name              string                 //The name of this job
-	Creator           string                 //The creator of this job. When execute, this user permission will be used
-	Description       string                 //Job description, can be empty
-	Admin             bool                   //If the creator has admin permission during the creation of this job. If this doesn't match with the runtime instance, this job wille be skipped
-	ExecutionInterval int64                  //Execuation interval in seconds
-	BaseTime          int64                  //Exeuction basetime. The next interval is calculated using (current time - base time ) % execution interval
-	JobType           string                 //Job type, accept {file/function}. If not set default to file
+	Name              string //The name of this job
+	Creator           string //The creator of this job. When execute, this user permission will be used
+	Description       string //Job description, can be empty
+	Admin             bool   //If the creator has admin permission during the creation of this job. If this doesn't match with the runtime instance, this job wille be skipped
+	ExecutionInterval int64  //Execuation interval in seconds
+	BaseTime          int64  //Exeuction basetime. The next interval is calculated using (current time - base time ) % execution interval
+	JobType           string //Job type, accept {file/function}. If not set default to file
+	FshID             string
 	ScriptFile        string                 //The script file being called. Can be an agi script (.agi / .js) or shell script (.bat or .sh)
 	ScriptFunc        func() (string, error) `json:"-"` //The target function to execute
 }

+ 4 - 1
mod/user/directoryHandler.go

@@ -4,7 +4,6 @@ import (
 	"errors"
 	"os"
 	"path/filepath"
-	"strings"
 
 	"imuslab.com/arozos/mod/filesystem"
 	fs "imuslab.com/arozos/mod/filesystem"
@@ -82,6 +81,7 @@ func (u *User) GetAllFileSystemHandler() []*fs.FileSystemHandler {
 	return results
 }
 
+/*
 func (u *User) VirtualPathToRealPath(vpath string) (string, error) {
 	//Get all usable filesystem handler from the user's home directory and permission groups
 	userFsHandlers := u.GetAllFileSystemHandler()
@@ -233,6 +233,7 @@ func (u *User) RealPathToVirtualPath(rpath string) (string, error) {
 
 	return "", errors.New("Unable to resolve realpath in virtual devices root path")
 }
+*/
 
 //Get a file system handler from a virtual path, this file system handler might not be the highest prioity one
 func (u *User) GetFileSystemHandlerFromVirtualPath(vpath string) (*fs.FileSystemHandler, error) {
@@ -241,6 +242,7 @@ func (u *User) GetFileSystemHandlerFromVirtualPath(vpath string) (*fs.FileSystem
 	return handler, err
 }
 
+/*
 func (u *User) GetFileSystemHandlerFromRealPath(rpath string) (*fs.FileSystemHandler, error) {
 	vpath, err := u.RealPathToVirtualPath(rpath)
 	if err != nil {
@@ -249,3 +251,4 @@ func (u *User) GetFileSystemHandlerFromRealPath(rpath string) (*fs.FileSystemHan
 
 	return u.GetFileSystemHandlerFromVirtualPath(vpath)
 }
+*/

+ 10 - 9
mod/user/permissionHandler.go

@@ -6,6 +6,7 @@ import (
 	"path/filepath"
 	"strings"
 
+	"imuslab.com/arozos/mod/filesystem/fsdef"
 	permission "imuslab.com/arozos/mod/permission"
 	storage "imuslab.com/arozos/mod/storage"
 )
@@ -93,31 +94,31 @@ func (u *User) GetInterfaceModules() []string {
 func (u *User) GetPathAccessPermission(vpath string) string {
 	fsid, _, err := getIDFromVirtualPath(filepath.ToSlash(vpath))
 	if err != nil {
-		return "denied"
+		return fsdef.FsDenied
 	}
 	topAccessRightStoragePool, err := u.GetHighestAccessRightStoragePool(fsid)
 	if err != nil {
-		return "denied"
+		return fsdef.FsDenied
 	}
 	if topAccessRightStoragePool.Owner == u.Username {
 		//This user own this storage pool. CHeck if the fs itself is readonly
 		fsHandler, _ := getHandlerFromID(u.GetAllFileSystemHandler(), fsid)
 		if fsHandler.ReadOnly {
-			return "readonly"
+			return fsdef.FsReadOnly
 		}
-		return "readwrite"
+		return fsdef.FsReadWrite
 	} else if topAccessRightStoragePool.Owner == "system" {
 		//System storage pool. Allow both read and write if the system handler is readwrite
 		fsHandler, _ := getHandlerFromID(u.GetAllFileSystemHandler(), fsid)
 		if fsHandler.ReadOnly {
-			return "readonly"
+			return fsdef.FsReadOnly
 		}
-		return "readwrite"
+		return fsdef.FsReadWrite
 	} else {
 		//This user do not own this storage pool. Use the pools' config
 		fsHandler, _ := getHandlerFromID(u.GetAllFileSystemHandler(), fsid)
 		if fsHandler.ReadOnly {
-			return "readonly"
+			return fsdef.FsReadOnly
 		}
 		return topAccessRightStoragePool.OtherPermission
 	}
@@ -126,7 +127,7 @@ func (u *User) GetPathAccessPermission(vpath string) string {
 //Helper function for checking permission
 func (u *User) CanRead(vpath string) bool {
 	rwp := u.GetPathAccessPermission(vpath)
-	if rwp == "readonly" || rwp == "readwrite" {
+	if rwp == fsdef.FsReadOnly || rwp == fsdef.FsReadWrite {
 		return true
 	} else {
 		return false
@@ -135,7 +136,7 @@ func (u *User) CanRead(vpath string) bool {
 
 func (u *User) CanWrite(vpath string) bool {
 	rwp := u.GetPathAccessPermission(vpath)
-	if rwp == "readwrite" {
+	if rwp == fsdef.FsReadWrite || rwp == fsdef.FsWriteOnly {
 		return true
 	} else {
 		return false

+ 22 - 24
mod/user/quota.go

@@ -5,7 +5,6 @@ import (
 	//"log"
 
 	fs "imuslab.com/arozos/mod/filesystem"
-	//quota "imuslab.com/arozos/mod/quota"
 )
 
 /*
@@ -17,53 +16,52 @@ import (
 */
 
 //Return the user quota information, returning used / total
-func (u *User) HaveSpaceFor(realpath string) bool {
-	if u.StorageQuota.HaveSpace(fs.GetFileSize(realpath)) {
+func (u *User) HaveSpaceFor(fsh *fs.FileSystemHandler, vpath string) bool {
+	realpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(vpath, u.Username)
+	if err != nil {
+		return false
+	}
+	if u.StorageQuota.HaveSpace(fsh.FileSystemAbstraction.GetFileSize(realpath)) {
 		return true
 	} else {
 		return false
 	}
 }
 
-func (u *User) SetOwnerOfFile(realpath string) error {
-
-	//Get handler from the path
-	fsHandler, err := u.GetFileSystemHandlerFromRealPath(realpath)
+func (u *User) SetOwnerOfFile(fsh *fs.FileSystemHandler, vpath string) error {
+	rpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(vpath, u.Username)
 	if err != nil {
 		return err
 	}
-
 	//Check if it is user structured. If yes, add the filesize to user's quota
-	if fsHandler.Hierarchy == "user" {
+	if fsh.Hierarchy == "user" {
 		//log.Println("Setting user ownership on: " + realpath)
-		u.StorageQuota.AllocateSpace(fs.GetFileSize(realpath))
+		u.StorageQuota.AllocateSpace(fsh.FileSystemAbstraction.GetFileSize(rpath))
 	}
 
 	//Add to the fshandler database of this file owner
-	err = fsHandler.CreateFileRecord(realpath, u.Username)
+	err = fsh.CreateFileRecord(rpath, u.Username)
 	return err
 }
 
-func (u *User) RemoveOwnershipFromFile(realpath string) error {
-
-	//Get handler from the path
-	fsHandler, err := u.GetFileSystemHandlerFromRealPath(realpath)
+func (u *User) RemoveOwnershipFromFile(fsh *fs.FileSystemHandler, vpath string) error {
+	realpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(vpath, u.Username)
 	if err != nil {
 		return err
 	}
 
 	//Check if it is user structured. If yes, add the filesize to user's quota
-	if fsHandler.Hierarchy == "user" {
+	if fsh.Hierarchy == "user" {
 		//log.Println("Removing user ownership on: " + realpath)
-		u.StorageQuota.ReclaimSpace(fs.GetFileSize(realpath))
+		u.StorageQuota.ReclaimSpace(fsh.FileSystemAbstraction.GetFileSize(realpath))
 	}
 
-	err = fsHandler.DeleteFileRecord(realpath)
+	err = fsh.DeleteFileRecord(realpath)
 	return err
 }
 
-func (u *User) IsOwnerOfFile(realpath string) bool {
-	owner := u.GetFileOwner(realpath)
+func (u *User) IsOwnerOfFile(fsh *fs.FileSystemHandler, vpath string) bool {
+	owner := u.GetFileOwner(fsh, vpath)
 	if owner == u.Username {
 		//This file is owned by this user
 		return true
@@ -72,18 +70,18 @@ func (u *User) IsOwnerOfFile(realpath string) bool {
 	}
 }
 
-func (u *User) GetFileOwner(realpath string) string {
-	fsHandler, err := u.GetFileSystemHandlerFromRealPath(realpath)
+func (u *User) GetFileOwner(fsh *fs.FileSystemHandler, vpath string) string {
+	realpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(vpath, u.Username)
 	if err != nil {
 		return ""
 	}
 
-	if fsHandler.UUID == "user" {
+	if fsh.UUID == "user" {
 		//This file is inside user's root. It must be this user's file
 		return u.Username
 	}
 
-	owner, err := fsHandler.GetFileRecord(realpath)
+	owner, err := fsh.GetFileRecord(realpath)
 	if err != nil {
 		//Error occured. Either this file is not tracked or this file has no owner
 		return ""

+ 23 - 15
mod/www/www.go

@@ -91,26 +91,20 @@ func (h *Handler) RouteRequest(w http.ResponseWriter, r *http.Request) {
 	webroot, err := h.GetUserWebRoot(userinfo.Username)
 	if err != nil {
 		//User do not have a correctly configured webroot. Serve instruction
-		w.WriteHeader(http.StatusInternalServerError)
-		if fileExists("./system/www/nowebroot.html") {
-			content, err := ioutil.ReadFile("./system/www/nowebroot.html")
-			if err != nil {
-				w.Write([]byte("500 - Internal Server Error"))
-			} else {
-				w.Write(content)
-			}
-
-		} else {
-			w.Write([]byte("500 - Internal Server Error"))
-		}
+		handleWebrootError(w)
 		return
 	}
 
 	//User webroot real path conversion
-	webrootRealpath, err := userinfo.VirtualPathToRealPath(webroot)
+	fsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(webroot)
 	if err != nil {
-		w.WriteHeader(http.StatusInternalServerError)
-		w.Write([]byte("500 - Internal Server Error"))
+		handleWebrootError(w)
+		return
+	}
+
+	webrootRealpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(webroot, userinfo.Username)
+	if err != nil {
+		handleWebrootError(w)
 		return
 	}
 
@@ -136,5 +130,19 @@ func (h *Handler) RouteRequest(w http.ResponseWriter, r *http.Request) {
 
 	//Serve the file
 	http.ServeFile(w, r, targetFilePath)
+}
+
+func handleWebrootError(w http.ResponseWriter) {
+	w.WriteHeader(http.StatusInternalServerError)
+	if fileExists("./system/www/nowebroot.html") {
+		content, err := ioutil.ReadFile("./system/www/nowebroot.html")
+		if err != nil {
+			w.Write([]byte("500 - Internal Server Error"))
+		} else {
+			w.Write(content)
+		}
 
+	} else {
+		w.Write([]byte("500 - Internal Server Error"))
+	}
 }

+ 1 - 1
startup.go

@@ -109,7 +109,7 @@ func RunStartup() {
 	system_resetpw_init()
 	mediaServer_init()
 	security_init()
-	backup_init()
+	//backup_init()
 	OAuthInit()        //Oauth system init
 	ldapInit()         //LDAP system init
 	notificationInit() //Notification system init

+ 23 - 5
storage.go

@@ -9,6 +9,7 @@ import (
 	"runtime"
 	"strings"
 
+	"imuslab.com/arozos/mod/filesystem/fsdef"
 	"imuslab.com/arozos/mod/permission"
 	"imuslab.com/arozos/mod/storage/bridge"
 
@@ -69,7 +70,7 @@ func LoadBaseStoragePool() error {
 			Name:       "Share",
 			Uuid:       "share",
 			Path:       filepath.ToSlash(filepath.Clean(*tmp_directory)) + "/",
-			Access:     "readonly",
+			Access:     fsdef.FsReadOnly,
 			Hierarchy:  "share",
 			Automount:  false,
 			Filesystem: "share",
@@ -107,7 +108,7 @@ func LoadBaseStoragePool() error {
 		Name:       "Loopback",
 		Uuid:       "loopback",
 		Path:       "http://192.168.1.214:8081/webdav/user",
-		Access:     "readwrite",
+		Access:     fsdef.FsReadWrite,
 		Hierarchy:  "public",
 		Automount:  false,
 		Filesystem: "webdav",
@@ -120,6 +121,23 @@ func LoadBaseStoragePool() error {
 		fsHandlers = append(fsHandlers, webdh)
 	}
 
+	webdh2, err := fs.NewFileSystemHandler(fs.FileSystemOption{
+		Name:       "CCNS",
+		Uuid:       "ccns",
+		Path:       "https://ccns.arozos.com:443/webdav/tmp",
+		Access:     fsdef.FsReadWrite,
+		Hierarchy:  "user",
+		Automount:  false,
+		Filesystem: "webdav",
+		Username:   "TC",
+		Password:   "fuckrub",
+	})
+	if err != nil {
+		log.Println(err.Error())
+	} else {
+		fsHandlers = append(fsHandlers, webdh2)
+	}
+
 	//Load all the storage config from file
 	rawConfig, err := ioutil.ReadFile(*storage_config_file)
 	if err != nil {
@@ -147,7 +165,7 @@ func LoadBaseStoragePool() error {
 	}
 
 	//Update the storage pool permission to readwrite
-	sp.OtherPermission = "readwrite"
+	sp.OtherPermission = fsdef.FsReadWrite
 	baseStoragePool = sp
 
 	return nil
@@ -201,7 +219,7 @@ func LoadStoragePoolForGroup(pg *permission.PermissionGroup) error {
 		}
 
 		//Set other permission to denied by default
-		sp.OtherPermission = "denied"
+		sp.OtherPermission = fsdef.FsDenied
 
 		//Assign storage pool to group
 		pg.StoragePool = sp
@@ -215,7 +233,7 @@ func LoadStoragePoolForGroup(pg *permission.PermissionGroup) error {
 			log.Println("Failed to create empty storage pool for group: ", pg.Name)
 		}
 		pg.StoragePool = sp
-		pg.StoragePool.OtherPermission = "denied"
+		pg.StoragePool.OtherPermission = fsdef.FsDenied
 	}
 
 	return nil

+ 1 - 1
web/Music/embedded.html

@@ -227,7 +227,7 @@
 		}
 
 		//Ignore all other input files.
-		playingFileInfo = ao_module_loadInputFiles()[0];
+		var playingFileInfo = ao_module_loadInputFiles()[0];
 		//Get the song title and meta data from server
 		var songInfo = [];
 		var songList = [];

+ 11 - 5
web/SystemAO/disk/diskprop.html

@@ -89,7 +89,7 @@
             </tr>
             <tr>
                 <td locale="diskinfo/hierarchy">
-                    Disk Hierarchy: 
+                    Hierarchy (Format): 
                 </td>
                 <td id="hierarchy">
                     
@@ -197,8 +197,8 @@
                         $("#usedSpaceInBytes").text(new Intl.NumberFormat('en-US').format(data.Used));
                         $("#usedSpaceInHumanReadableFormat").text(bytesToSize(data.Used));
 
-                        $("#usableSpaceInBytes").text(new Intl.NumberFormat('en-US').format(data.Avilable));
-                        $("#usableSpaceInHumanReadableFormat").text(bytesToSize(data.Avilable));
+                        $("#usableSpaceInBytes").text(new Intl.NumberFormat('en-US').format(data.Available));
+                        $("#usableSpaceInHumanReadableFormat").text(bytesToSize(data.Available));
 
                         $("#totalSpaceInBytes").text(new Intl.NumberFormat('en-US').format(data.Total));
                         $("#totalSpaceInHumanReadableFormat").text(bytesToSize(data.Total));
@@ -206,7 +206,7 @@
                         $("#phydisk").text(data.PhysicalDevice + "/");
                         var s = data.MountingHierarchy;
                         s = s[0].toUpperCase() + s.slice(1);
-                        $("#hierarchy").text(applocale.getString("hierarchy/" + s, s));
+                        $("#hierarchy").text(applocale.getString("hierarchy/" + s, s) + ` (${data.FileSystemType.toUpperCase()})`);
                         
                         $("#totalUsedSpace").css("width", (data.Used / data.Total) * 100 + "%");
                     }
@@ -221,9 +221,15 @@
                             $("#usedVirtualSpaceInByte").text("Not Available");
                             $("#usedVirtualSpaceInHumanReadableFormat").text("");
                         }
+
+                        if (diskInfo.Used == 0){
+                            //Network or special drive. Use user space as usedSpace
+                            $("#usedSpaceInBytes").text(new Intl.NumberFormat('en-US').format(folderdata.Filesize));
+                            $("#usedSpaceInHumanReadableFormat").text(bytesToSize(folderdata.Filesize));
+                        }
                        
                         
-                        if (data.Total != undefined){
+                        if (data.Total != undefined && data.Total > 0){
                             $("#userUsedSpace").css("width", (folderdata.Filesize / data.Total) * 100 + "%");
                         }else{
                             //Error when reading disk size. Just make it full width

+ 3 - 3
web/SystemAO/locale/disk_properties.json

@@ -10,7 +10,7 @@
                 "title/desc":"關於此虛擬儲存裝置對應之磁碟機掛載點",
 
                 "diskinfo/physical":"物理磁碟機",
-                "diskinfo/hierarchy":"儲存裝置結構",
+                "diskinfo/hierarchy":"儲存裝置結構(格式)",
 
                 "hierarchy/User":"使用者分隔",
                 "hierarchy/Public":"共用磁碟區",
@@ -42,7 +42,7 @@
                 "title/desc":"關於此虛擬儲存裝置對應之磁碟機掛載點",
 
                 "diskinfo/physical":"物理磁碟機",
-                "diskinfo/hierarchy":"儲存裝置結構",
+                "diskinfo/hierarchy":"儲存裝置結構(格式)",
 
                 "hierarchy/User":"使用者分隔",
                 "hierarchy/Public":"共用磁碟區",
@@ -74,7 +74,7 @@
                 "title/desc":"关于此虚拟储存装置对应的硬盘挂载点",
 
                 "diskinfo/physical":"物理硬盘",
-                "diskinfo/hierarchy":"储存装置结构",
+                "diskinfo/hierarchy":"储存装置结构(格式)",
 
                 "hierarchy/User":"使用者分隔",
                 "hierarchy/Public":"共用硬盘",