| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 | package diskmgimport (	"encoding/json"	"errors"	"log"	"net/http"	"os/exec"	"path/filepath"	"regexp"	"runtime"	"strings"	"time"	db "imuslab.com/arozos/mod/database"	fs "imuslab.com/arozos/mod/filesystem")type Lsblk struct {	Blockdevices []struct {		Name       string      `json:"name"`		MajMin     string      `json:"maj:min"`		Rm         bool        `json:"rm"`		Size       int64       `json:"size"`		Ro         bool        `json:"ro"`		Type       string      `json:"type"`		Mountpoint interface{} `json:"mountpoint"`		Children   []struct {			Name       string `json:"name"`			MajMin     string `json:"maj:min"`			Rm         bool   `json:"rm"`			Size       int64  `json:"size"`			Ro         bool   `json:"ro"`			Type       string `json:"type"`			Mountpoint string `json:"mountpoint"`		} `json:"children"`	} `json:"blockdevices"`}type LsblkF struct {	Blockdevices []struct {		Name       string      `json:"name"`		Fstype     interface{} `json:"fstype"`		Label      interface{} `json:"label"`		UUID       interface{} `json:"uuid"`		Fsavail    interface{} `json:"fsavail"`		Fsuse      interface{} `json:"fsuse%"`		Mountpoint interface{} `json:"mountpoint"`		Children   []struct {			Name       string      `json:"name"`			Fstype     string      `json:"fstype"`			Label      interface{} `json:"label"`			UUID       string      `json:"uuid"`			Fsavail    string      `json:"fsavail"`			Fsuse      string      `json:"fsuse%"`			Mountpoint string      `json:"mountpoint"`		} `json:"children"`	} `json:"blockdevices"`}var (	supportedFormats = []string{"ntfs", "vfat", "ext4", "ext3", "btrfs"})/*	Diskmg View Generator	This section of the code is a direct translation of the original	AOB's diskmg.php and diskmgWin.php.	If you find any bugs in these code, just remember they are legacy	code and rewriting the whole thing will save you a lot more time.*/func HandleView(w http.ResponseWriter, r *http.Request) {	partition, _ := mv(r, "partition", false)	detailMode := (partition != "")	if runtime.GOOS == "windows" {		//Windows. Use DiskmgWin binary		if fileExists("./system/disk/diskmg/DiskmgWin.exe") {			out := ""			if detailMode {				cmd := exec.Command("./system/disk/diskmg/DiskmgWin.exe", "-d")				o, err := cmd.CombinedOutput()				if err != nil {					sendErrorResponse(w, "Permission Denied")					return				}				out = string(o)			} else {				cmd := exec.Command("./system/disk/diskmg/DiskmgWin.exe")				o, err := cmd.CombinedOutput()				if err != nil {					sendErrorResponse(w, "Permission Denied")					return				}				out = string(o)			}			out = strings.TrimSpace(out)			lines := strings.Split(out, ";")			results := [][]string{}			for _, line := range lines {				data := strings.Split(line, ",")				if len(data) > 0 && data[0] != "" {					results = append(results, data)				}			}			js, _ := json.Marshal(results)			sendJSONResponse(w, string(js))		} else {			log.Println("system/disk/diskmg/DiskmgWin.exe NOT FOUND. Unable to load Window's disk information")			sendErrorResponse(w, "DiskmgWin.exe not found")			return		}	} else {		//Linux. Use lsblk and df to check volume info		partition := new(Lsblk)		format := new(LsblkF)		df := ""		//Get partition information		cmd := exec.Command("lsblk", "-b", "--json")		o, err := cmd.CombinedOutput()		if err != nil {			sendErrorResponse(w, err.Error())			return		}		err = json.Unmarshal(o, &partition)		if err != nil {			sendErrorResponse(w, err.Error())			return		}		//Get format info		cmd = exec.Command("lsblk", "-f", "-b", "--json")		o, err = cmd.CombinedOutput()		if err != nil {			sendErrorResponse(w, err.Error())			return		}		err = json.Unmarshal(o, &format)		if err != nil {			sendErrorResponse(w, err.Error())			return		}		//Get df info		cmd = exec.Command("df")		o, err = cmd.CombinedOutput()		if err != nil {			sendErrorResponse(w, err.Error())			return		}		df = string(o)		//Filter the df information		for strings.Contains(df, "  ") {			df = strings.ReplaceAll(df, "  ", " ")		}		dflines := strings.Split(df, "\n")		parsedDf := [][]string{}		for _, line := range dflines {			linedata := strings.Split(line, " ")			parsedDf = append(parsedDf, linedata)		}		//Throw away the table header		parsedDf = parsedDf[1:]		js, _ := json.Marshal([]interface{}{			partition,			format,			parsedDf,		})		sendJSONResponse(w, string(js))	}}/*	Mounting a given partition or devices	Manual translated from mountTool.php	Require GET parameter: dev / format / mnt*/func HandleMount(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileSystemHandler) {	if runtime.GOOS == "linux" {		targetDev, _ := mv(r, "dev", false)		format, err := mv(r, "format", false)		if err != nil {			sendErrorResponse(w, "format not defined")			return		}		mountPt, err := mv(r, "mnt", false)		if err != nil {			sendErrorResponse(w, "Mount Point not defined")			return		}		//Check if device is valid		ok, devID := checkDeviceValid(targetDev)		if !ok {			sendErrorResponse(w, "Device name is not valid")			return		}		//Check if the given format is supported		mountingTool := ""		if format == "ntfs" {			mountingTool = "ntfs-3g"		} else if format == "ext4" {			mountingTool = "ext4"		} else if format == "vfat" {			mountingTool = "vfat"		} else if format == "brtfs" {			mountingTool = "brtfs"		} else {			sendErrorResponse(w, "Format not supported")			return		}		//Check if mount point exists, only support /medoa/*		safeMountPoint := filepath.Clean(strings.ReplaceAll(mountPt, "../", ""))		if !fileExists(safeMountPoint) {			sendErrorResponse(w, "Mount point not exists, given: "+safeMountPoint)			return		}		//Check if action is mount or umount		umount, _ := mv(r, "umount", false)		if umount == "true" {			//Unmount the given mountpoint			output, err := Unmount(safeMountPoint, fsHandlers)			if err != nil {				sendErrorResponse(w, output)				return			}			sendTextResponse(w, output)		} else {			o, err := Mount(devID, safeMountPoint, mountingTool, fsHandlers)			if err != nil {				sendErrorResponse(w, o)				return			}			sendTextResponse(w, o)		}	} else {		sendErrorResponse(w, "Platform not supported: "+runtime.GOOS)		return	}}/*	Format Tool	Manual translation from AOB's formatTool.php*/func HandleFormat(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileSystemHandler) {	dev, err := mv(r, "dev", true)	if err != nil {		sendErrorResponse(w, "dev not defined")		return	}	format, err := mv(r, "format", true)	if err != nil {		sendErrorResponse(w, "format not defined")		return	}	if runtime.GOOS == "windows" {		sendErrorResponse(w, "This function is Linux Only")		return	}	//Check if format is supported	if !inArray(supportedFormats, format) {		sendErrorResponse(w, "Format not supported")		return	}	//Check if device is valid	ok, devID := checkDeviceValid(dev)	if !ok {		sendErrorResponse(w, "Device name is not valid")		return	}	//Check if it is mounted. If yes, umount it	mounted, err := checkDeviceMounted(devID)	if err != nil {		//Fail to check if disk mounted		log.Println(err.Error())		sendErrorResponse(w, "Failed to check disk mount status")		return	}	//This drive is still mounted. Unmount it	if mounted {		//Close all the fsHandler related to this disk		mountpt, err := getDeviceMountPoint(devID)		if err != nil {			sendErrorResponse(w, err.Error())			return		}		log.Println("Unmounting " + mountpt + " for format")		//Unmount the devices		out, err := Unmount(mountpt, fsHandlers)		if err != nil {			sendErrorResponse(w, out)			return		}	}	//Format the drive	var cmd *exec.Cmd	if format == "ntfs" {		cmd = exec.Command("mkfs.ntfs", "-f", "/dev/"+devID)	} else if format == "vfat" {		cmd = exec.Command("mkfs.vfat", "/dev/"+devID)	} else if format == "ext4" {		cmd = exec.Command("mkfs.ext4", "-F", "/dev/"+devID)	} else if format == "ext3" {		sendErrorResponse(w, "Format to ext3 is Work In Progress")	} else if format == "btrfs" {		sendErrorResponse(w, "Format to btrfs is Work In Progress")	} else {		sendErrorResponse(w, "Format tyoe not supported")	}	//Execute format comamnd	log.Println("Formatting of " + "/dev/" + devID + " Started")	output, err := cmd.CombinedOutput()	if err != nil {		log.Println("Format failed: " + string(output))		sendErrorResponse(w, string(output))		return	}	//Reply ok	log.Println(string(output))	//Let the system to reload the disk	time.Sleep(2 * time.Second)	sendOK(w)}func Mount(devID string, mountpt string, mountingTool string, fsHandlers []*fs.FileSystemHandler) (string, error) {	//Loop each fsHandler. If exists one that fits and Closed, reopen it	for _, fsh := range fsHandlers {		if strings.Contains(filepath.ToSlash(fsh.Path), filepath.ToSlash(mountpt)) {			//Re-open the file system database and set its flag to Open			fsdbPath := filepath.ToSlash(filepath.Clean(fsh.Path)) + "/aofs.db"			dbObject, err := db.NewDatabase(fsdbPath, false)			if err != nil {				continue			}			fsh.FilesystemDatabase = dbObject			fsh.Closed = false		}	}	log.Println("Executing Mount Command: ", "mount", "-t", mountingTool, "/dev/"+devID, mountpt)	cmd := exec.Command("mount", "-t", mountingTool, "/dev/"+devID, mountpt)	o, err := cmd.CombinedOutput()	if err != nil {		log.Println("Failed to mount "+devID, string(o))	}	return string(o), err}//Unmount a given mountpointfunc Unmount(mountpt string, fsHandlers []*fs.FileSystemHandler) (string, error) {	//Unmount the fsHandlers that related to this mountpt	for _, fsh := range fsHandlers {		if strings.Contains(filepath.ToSlash(fsh.Path), filepath.ToSlash(mountpt)) {			//Close this file system handler			fsh.FilesystemDatabase.Close()			fsh.Closed = true		}	}	log.Println("Executing Umount Command: ", "umount", mountpt)	cmd := exec.Command("umount", mountpt)	o, err := cmd.CombinedOutput()	return string(o), err}//Return a list of mountable directoryfunc HandleListMountPoints(w http.ResponseWriter, r *http.Request) {	mp, _ := filepath.Glob("/media/*")	js, _ := json.Marshal(mp)	sendJSONResponse(w, string(js))}//Check if the device is mountedfunc checkDeviceMounted(devname string) (bool, error) {	cmd := exec.Command("bash", "-c", "lsblk -f -b --json | grep "+devname)	output, err := cmd.CombinedOutput()	if err != nil {		return false, err	}	//Convert the json map to generic string interface map	jsonMap := make(map[string]interface{})	err = json.Unmarshal(output, &jsonMap)	if err != nil {		return false, err	}	if jsonMap["mountpoint"] != nil {		return true, nil	} else {		return false, nil	}}func getDeviceMountPoint(devname string) (string, error) {	cmd := exec.Command("bash", "-c", "lsblk -f -b --json | grep "+devname)	output, err := cmd.CombinedOutput()	if err != nil {		return "", errors.New("Device not mounted")	}	//Convert the json map to generic string interface map	jsonMap := make(map[string]interface{})	err = json.Unmarshal(output, &jsonMap)	if err != nil {		return "", errors.New("Pharse mountpoint error")	}	if jsonMap["mountpoint"] != nil {		return jsonMap["mountpoint"].(string), nil	} else {		return "", errors.New("Unable to get mountpoint from lsblk")	}}//Check device valid, only usable in linuxfunc checkDeviceValid(devname string) (bool, string) {	//Check if the device name is valid	match, _ := regexp.MatchString("sd[a-z][1-9]", devname)	if !match {		return false, ""	}	//Extract the device name from string	re := regexp.MustCompile(`sd[a-z][1-9]`)	devID := re.FindString(devname)	if !fileExists("/dev/" + devID) {		return false, ""	}	return true, devID}func HandlePlatform(w http.ResponseWriter, r *http.Request) {	js, _ := json.Marshal(runtime.GOOS)	sendJSONResponse(w, string(js))}
 |