123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- package diskcapacity
- import (
- "encoding/json"
- "errors"
- "net/http"
- "path/filepath"
- "runtime"
- "strings"
- "log"
- "strconv"
- "os/exec"
- "imuslab.com/arozos/mod/common"
- "imuslab.com/arozos/mod/disk/diskspace"
- "imuslab.com/arozos/mod/user"
- )
- /*
- Disk Capacity
- This is a simple module to check how many storage space is remaining
- on a given directory in accessiable file system paths
- Author: tobychui
- */
- type Resolver struct {
- UserHandler *user.UserHandler
- }
- 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
- }
- //Create a new Capacity Resolver with the given user handler
- func NewCapacityResolver(u *user.UserHandler) *Resolver {
- return &Resolver{
- UserHandler: u,
- }
- }
- func (cr *Resolver) HandleCapacityResolving(w http.ResponseWriter, r *http.Request) {
- //Check if the request user is authenticated
- userinfo, err := cr.UserHandler.GetUserInfoFromRequest(w, r)
- if err != nil {
- common.SendErrorResponse(w, "User not logged in")
- return
- }
- //Get vpath from paramter
- vpath, err := common.Mv(r, "path", true)
- if err != nil {
- common.SendErrorResponse(w, "Vpath is not defined")
- return
- }
- capinfo, err := cr.ResolveCapacityInfo(userinfo.Username, vpath)
- if err != nil {
- common.SendErrorResponse(w, "Unable to resolve path capacity information: "+err.Error())
- return
- }
- //Get Storage Hierarcy
- fsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(vpath)
- if err != nil {
- capinfo.MountingHierarchy = "Unknown"
- } else {
- capinfo.MountingHierarchy = fsh.Hierarchy
- }
- //Send the requested path capacity information
- js, _ := json.Marshal(capinfo)
- common.SendJSONResponse(w, string(js))
- }
- func (cr *Resolver) ResolveCapacityInfo(username string, vpath string) (*Capacity, error) {
- //Resolve the vpath for this user
- userinfo, err := cr.UserHandler.GetUserInfoFromUsername(username)
- if err != nil {
- return nil, err
- }
- realpath, err := userinfo.VirtualPathToRealPath(vpath)
- if err != nil {
- return nil, err
- }
- realpath = filepath.ToSlash(filepath.Clean(realpath))
- return cr.GetCapacityInfo(realpath)
- }
- func (cr *Resolver) GetCapacityInfo(realpath string) (*Capacity, error) {
- rpathAbs, err := filepath.Abs(realpath)
- if err != nil {
- return nil, err
- }
- if runtime.GOOS == "windows" {
- //Windows
- //Extract disk ID from path
- rpathAbs = filepath.ToSlash(filepath.Clean(rpathAbs))
- diskRoot := strings.Split(rpathAbs, "/")[0]
- //Match the disk space info generated from diskspace
- logicDiskInfo := diskspace.GetAllLogicDiskInfo()
- for _, ldi := range logicDiskInfo {
- if strings.TrimSpace(ldi.Device) == strings.TrimSpace(diskRoot) {
- //Matching device ID
- return &Capacity{
- PhysicalDevice: ldi.Device,
- Used: ldi.Used,
- Avilable: ldi.Available,
- Total: ldi.Volume,
- }, nil
- }
- }
- } else {
- //Assume Linux or Mac
- //Use command: df -P {abs_path}
- cmd := exec.Command("df", "-P", rpathAbs)
- log.Println("df", "-P", rpathAbs)
- out, err := cmd.CombinedOutput()
- if err != nil {
- return nil, err
- }
- //Get the last line of the output
- diskInfo := strings.TrimSpace(string(out))
- tmp := strings.Split(diskInfo, "\n")
- targetDiskInfo := strings.Join(tmp[len(tmp) - 1:], " ");
- for strings.Contains(targetDiskInfo, " "){
- targetDiskInfo = strings.ReplaceAll(targetDiskInfo, " ", " ")
- }
- diskInfoSlice := strings.Split(targetDiskInfo, " ")
- if len(diskInfoSlice) < 4{
- return nil, errors.New("Malformed output for df -P")
- }
- //Extract capacity information from df output
- total, err := strconv.ParseInt(diskInfoSlice[1], 10, 64)
- if err != nil{
- return nil, errors.New("Malformed output for df -P")
- }
- used, err := strconv.ParseInt(diskInfoSlice[2], 10, 64)
- if err != nil{
- return nil, errors.New("Malformed output for df -P")
- }
- availbe, err := strconv.ParseInt(diskInfoSlice[3], 10, 64)
- if err != nil{
- return nil, errors.New("Malformed output for df -P")
- }
- //Return the capacity info struct, capacity is reported in 1024 bytes block
- return &Capacity{
- PhysicalDevice: diskInfoSlice[0],
- Used: used * 1024,
- Avilable: availbe * 1024,
- Total: total * 1024,
- }, nil
- }
- return nil, errors.New("Unable to resolve matching disk capacity information")
- }
|