package main import ( "archive/zip" "encoding/base64" "encoding/json" "fmt" "io" "io/ioutil" "log" "encoding/hex" "os" "runtime" "path" "path/filepath" "reflect" "strings" "time" ) func in_array(val interface{}, array interface{}) (exists bool, index int) { exists = false index = -1 switch reflect.TypeOf(array).Kind() { case reflect.Slice: s := reflect.ValueOf(array) for i := 0; i < s.Len(); i++ { if reflect.DeepEqual(val, s.Index(i).Interface()) == true { index = i exists = true return } } } return } func file_exists(path string) bool { if _, err := os.Stat(path); os.IsNotExist(err) { return false } return true } func file_get_contents(path string) string { dat, err := ioutil.ReadFile(path) if err != nil { panic("Unable to read file: " + path) } return (string(dat)) } func writeLog(filepath string, prefix string, message string) bool { f, err := os.OpenFile(filepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.Println(err) } defer f.Close() logger := log.New(f, prefix, log.LstdFlags) logger.Println(message) return true } /* Functions realted to UM filename conversion and path parsing */ func UMpath2UTF8path(rawname string) string{ //Check seperator sep := "/" if runtime.GOOS == "windows" { sep = "\\" } pathChunks := strings.Split(rawname,sep) var newPath []string for i := 0; i","-", "|","-", "?","-", ":","-") safeName := replacer.Replace(string(s)) return safeName } func hex2bin(s string) ([]byte, error) { ret, err := hex.DecodeString(s) return ret, err } func bin2hex(s string) (string) { src := []byte(s) encodedStr := hex.EncodeToString(src) return encodedStr; } func compress(source, target string) error { zipfile, err := os.Create(target) if err != nil { return err } defer zipfile.Close() archive := zip.NewWriter(zipfile) defer archive.Close() info, err := os.Stat(source) if err != nil { return nil } var baseDir string if info.IsDir() { baseDir = filepath.Base(source) } filepath.Walk(source, func(path string, info os.FileInfo, err error) error { if err != nil { return err } header, err := zip.FileInfoHeader(info) if err != nil { return err } if baseDir != "" { rawHeaderName := filepath.Join(baseDir, strings.TrimPrefix(path, source)) convertedName := UMpath2UTF8path(rawHeaderName); header.Name = convertedName } if info.IsDir() { header.Name += "/" } else { header.Method = zip.Deflate } writer, err := archive.CreateHeader(header) if err != nil { return err } if info.IsDir() { return nil } file, err := os.Open(path) if err != nil { return err } defer file.Close() _, err = io.Copy(writer, file) return err }) return err } func unzip(archive, target string) error { reader, err := zip.OpenReader(archive) if err != nil { return err } if err := os.MkdirAll(target, 0755); err != nil { return err } for _, file := range reader.File { path := filepath.Join(target, file.Name) if file.FileInfo().IsDir() { os.MkdirAll(path, file.Mode()) continue } fileReader, err := file.Open() if err != nil { return err } defer fileReader.Close() targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode()) if err != nil { return err } defer targetFile.Close() if _, err := io.Copy(targetFile, fileReader); err != nil { return err } } return nil } func getTimestamp() string { t := time.Now() return (t.Format("2006-01-02 150405")) } func decodeBase64(base64string string) string { l, err := base64.StdEncoding.DecodeString(base64string) if err != nil { panic(err) } return string(l) } func moveLogFile(logfile string, target string, uuid string) { //If then else is used to prevent invalid move target if target == "done" { os.Rename(logfile, "log/done/"+uuid+".log") os.Chmod("log/done/"+uuid+".log", 0777) //Unlock the file for read write from php } else if target == "error" { os.Rename(logfile, "log/error/"+uuid+".log") os.Chmod("log/error/"+uuid+".log", 0777) //Unlock the file for read write from php } else { //What happened? panic("ERROR. Undefined log file sattle location.") } } func finishFileOperation(logfile string, uuid string) { //Finishing the file operation. //time.Sleep(20000 * time.Millisecond) //Added this line for debug purpose writeLog(logfile, "[done] ", "Task finished successfully") moveLogFile(logfile, "done", uuid) fmt.Println("Done") } func isDir(path string) bool { file, _ := os.Open(path) if fi, err := file.Stat(); err != nil || fi.IsDir() { return true } file.Close() return false } func raiseError(logfile string, uuid string, errMsg string) { writeLog(logfile, "[error] ", errMsg) moveLogFile(logfile, "error", uuid) panic("ERROR. " + errMsg) } func ChmodR(path string) error { return filepath.Walk(path, func(name string, info os.FileInfo, err error) error { if err == nil { err = os.Chmod(name, 0755) } return err }) } func main() { //Init the log folder if it doesn't exists if !file_exists("log/") { os.MkdirAll("log/", 0777) } if !file_exists("log/done/") { os.MkdirAll("log/done/", 0777) } if !file_exists("log/error/") { os.MkdirAll("log/error/", 0777) } //Check argument if satisfied if len(os.Args) < 3 { fmt.Println("<>") fmt.Println("Usage: fszip {uuid} {command_in_base64_JSON}") fmt.Println("Command must be an array containing [{'zip' / 'unzip'},{filepath},{zip_target}]") return } startSettings := os.Args[1:] uuid := startSettings[0] encodedCommand := startSettings[1] decodedCommand := decodeBase64(encodedCommand) filename := uuid + ".log" logfile := "log/" + filename var command []string //Check if the given uuid already exists. If yes, terminate the execution if file_exists("log/"+uuid+".log") || file_exists("log/done/"+uuid+".log") || file_exists("log/error/"+uuid+".log") { panic("ERROR. Given uuid already exists.") } //Create the log file for this task writeLog(logfile, "[init] ", "Task created on "+getTimestamp()) //Parse the JSON string into readable array err := json.Unmarshal([]byte(decodedCommand), &command) if err != nil { writeLog(logfile, "[error] ", "Unable to parse JSON string.") moveLogFile(logfile, "error", uuid) panic("ERROR. Unable to parse JSON string.") } //Check opr if command[0] == "zip" { //Start the compression process for the given path //Command structure: ["zip","{source}","{target} (Pass in empty string for default location)"] //Check if the given filepath exists if !file_exists(command[1]) { raiseError(logfile, uuid, "Source not exists.") } inpath := command[1] //Check if inpath end with "/". If yes, remove it if inpath[len(inpath)-1:] == "/" { inpath = inpath[0 : len(inpath)-1] } outpath := command[2] //File exists. Check if it is a folder or not. if outpath != "" { //If there is a defined export filepath, check if the parent dir exists. If not, create it if !file_exists(path.Dir(outpath)) { os.MkdirAll(path.Dir(outpath), 0755) } } else { //There is no defined export path. Export next to the source as zip. if isDir(command[1]) { outpath = path.Dir(path.Dir(inpath)) + "/" + path.Base(inpath) + ".zip" } else { outpath = path.Dir(inpath) + "/" + strings.TrimSuffix(inpath, filepath.Ext(inpath)) + ".zip" } } if file_exists(outpath) { raiseError(logfile, uuid, "Output file already exists.") } compress(inpath, outpath) os.Chmod(outpath, 0777) finishFileOperation(logfile, uuid) } else if command[0] == "unzip" { //Unzip a given filepath //command structure: ["unzip","{source}","{target}"] if !file_exists(command[1]) { raiseError(logfile, uuid, "Source not exists.") } inpath := command[1] outpath := command[2] if outpath == "" { //If unzup target is empty string, unzip to the current directory which the script is executed outpath = "./" } //Check if the input path is a zip file. If not, post a warning into the log file if filepath.Ext(inpath) != ".zip" { writeLog(logfile, "[warning] ", "The given file might not be a zip file. Trying to open it anyway. File ext given: "+filepath.Ext(inpath)) } //Create outpath if it doesn't exists if !file_exists(outpath) { os.MkdirAll(outpath, 0755) } unzip(inpath, outpath) if isDir(outpath) { ChmodR(outpath) } else { os.Chmod(outpath, 0755) } finishFileOperation(logfile, uuid) } }