main.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. package main
  2. import (
  3. "archive/zip"
  4. "encoding/base64"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "log"
  10. "encoding/hex"
  11. "os"
  12. "runtime"
  13. "path"
  14. "path/filepath"
  15. "reflect"
  16. "strings"
  17. "time"
  18. )
  19. func in_array(val interface{}, array interface{}) (exists bool, index int) {
  20. exists = false
  21. index = -1
  22. switch reflect.TypeOf(array).Kind() {
  23. case reflect.Slice:
  24. s := reflect.ValueOf(array)
  25. for i := 0; i < s.Len(); i++ {
  26. if reflect.DeepEqual(val, s.Index(i).Interface()) == true {
  27. index = i
  28. exists = true
  29. return
  30. }
  31. }
  32. }
  33. return
  34. }
  35. func file_exists(path string) bool {
  36. if _, err := os.Stat(path); os.IsNotExist(err) {
  37. return false
  38. }
  39. return true
  40. }
  41. func file_get_contents(path string) string {
  42. dat, err := ioutil.ReadFile(path)
  43. if err != nil {
  44. panic("Unable to read file: " + path)
  45. }
  46. return (string(dat))
  47. }
  48. func writeLog(filepath string, prefix string, message string) bool {
  49. f, err := os.OpenFile(filepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
  50. if err != nil {
  51. log.Println(err)
  52. }
  53. defer f.Close()
  54. logger := log.New(f, prefix, log.LstdFlags)
  55. logger.Println(message)
  56. return true
  57. }
  58. /*
  59. Functions realted to UM filename conversion and path parsing
  60. */
  61. func UMpath2UTF8path(rawname string) string{
  62. //Check seperator
  63. sep := "/"
  64. if runtime.GOOS == "windows" {
  65. sep = "\\"
  66. }
  67. pathChunks := strings.Split(rawname,sep)
  68. var newPath []string
  69. for i := 0; i<len(pathChunks); i++{
  70. //For each path chunks, convert it to UTF8 representation
  71. thisChunk := pathChunks[i];
  72. if (strings.Contains(thisChunk,".")){
  73. filename := thisChunk;
  74. extension := filepath.Ext(filename)
  75. name := thisChunk[0 : len(thisChunk)-len(extension)]
  76. if name[0:5] == "inith"{
  77. //This might be a umfilename
  78. hexNameOnly := strings.Replace(name,"inith","",1)
  79. r, e := hex2bin(hexNameOnly)
  80. if (e != nil){
  81. //Assume it is normal filename.
  82. newPath = append(newPath,thisChunk)
  83. }else{
  84. decodedName := string(r) + extension
  85. newPath = append(newPath,getSafeFilename(decodedName))
  86. }
  87. }else{
  88. //This is not an umfilename
  89. newPath = append(newPath,thisChunk)
  90. }
  91. }else{
  92. //This might be a folder name
  93. r, e := hex2bin(thisChunk)
  94. if e != nil{
  95. //This path is not hexified
  96. newPath = append(newPath,thisChunk)
  97. }else{
  98. //This path is hexified. Append the converted info into newpath
  99. newPath = append(newPath,getSafeFilename(string(r)))
  100. }
  101. }
  102. }
  103. return strings.Join(newPath,sep)
  104. }
  105. func getSafeFilename(s string) string{
  106. replacer := strings.NewReplacer("/", "", "\\","", "@","-", "&","-", "*","-", "<","-", ">","-", "|","-", "?","-", ":","-")
  107. safeName := replacer.Replace(string(s))
  108. return safeName
  109. }
  110. func hex2bin(s string) ([]byte, error) {
  111. ret, err := hex.DecodeString(s)
  112. return ret, err
  113. }
  114. func bin2hex(s string) (string) {
  115. src := []byte(s)
  116. encodedStr := hex.EncodeToString(src)
  117. return encodedStr;
  118. }
  119. func compress(source, target string) error {
  120. zipfile, err := os.Create(target)
  121. if err != nil {
  122. return err
  123. }
  124. defer zipfile.Close()
  125. archive := zip.NewWriter(zipfile)
  126. defer archive.Close()
  127. info, err := os.Stat(source)
  128. if err != nil {
  129. return nil
  130. }
  131. var baseDir string
  132. if info.IsDir() {
  133. baseDir = filepath.Base(source)
  134. }
  135. filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
  136. if err != nil {
  137. return err
  138. }
  139. header, err := zip.FileInfoHeader(info)
  140. if err != nil {
  141. return err
  142. }
  143. if baseDir != "" {
  144. rawHeaderName := filepath.Join(baseDir, strings.TrimPrefix(path, source))
  145. convertedName := UMpath2UTF8path(rawHeaderName);
  146. header.Name = convertedName
  147. }
  148. if info.IsDir() {
  149. header.Name += "/"
  150. } else {
  151. header.Method = zip.Deflate
  152. }
  153. writer, err := archive.CreateHeader(header)
  154. if err != nil {
  155. return err
  156. }
  157. if info.IsDir() {
  158. return nil
  159. }
  160. file, err := os.Open(path)
  161. if err != nil {
  162. return err
  163. }
  164. defer file.Close()
  165. _, err = io.Copy(writer, file)
  166. return err
  167. })
  168. return err
  169. }
  170. func unzip(archive, target string) error {
  171. reader, err := zip.OpenReader(archive)
  172. if err != nil {
  173. return err
  174. }
  175. if err := os.MkdirAll(target, 0755); err != nil {
  176. return err
  177. }
  178. for _, file := range reader.File {
  179. path := filepath.Join(target, file.Name)
  180. if file.FileInfo().IsDir() {
  181. os.MkdirAll(path, file.Mode())
  182. continue
  183. }
  184. fileReader, err := file.Open()
  185. if err != nil {
  186. return err
  187. }
  188. defer fileReader.Close()
  189. targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
  190. if err != nil {
  191. return err
  192. }
  193. defer targetFile.Close()
  194. if _, err := io.Copy(targetFile, fileReader); err != nil {
  195. return err
  196. }
  197. }
  198. return nil
  199. }
  200. func getTimestamp() string {
  201. t := time.Now()
  202. return (t.Format("2006-01-02 150405"))
  203. }
  204. func decodeBase64(base64string string) string {
  205. l, err := base64.StdEncoding.DecodeString(base64string)
  206. if err != nil {
  207. panic(err)
  208. }
  209. return string(l)
  210. }
  211. func moveLogFile(logfile string, target string, uuid string) {
  212. //If then else is used to prevent invalid move target
  213. if target == "done" {
  214. os.Rename(logfile, "log/done/"+uuid+".log")
  215. os.Chmod("log/done/"+uuid+".log", 0777) //Unlock the file for read write from php
  216. } else if target == "error" {
  217. os.Rename(logfile, "log/error/"+uuid+".log")
  218. os.Chmod("log/error/"+uuid+".log", 0777) //Unlock the file for read write from php
  219. } else {
  220. //What happened?
  221. panic("ERROR. Undefined log file sattle location.")
  222. }
  223. }
  224. func finishFileOperation(logfile string, uuid string) {
  225. //Finishing the file operation.
  226. //time.Sleep(20000 * time.Millisecond) //Added this line for debug purpose
  227. writeLog(logfile, "[done] ", "Task finished successfully")
  228. moveLogFile(logfile, "done", uuid)
  229. fmt.Println("Done")
  230. }
  231. func isDir(path string) bool {
  232. file, _ := os.Open(path)
  233. if fi, err := file.Stat(); err != nil || fi.IsDir() {
  234. return true
  235. }
  236. file.Close()
  237. return false
  238. }
  239. func raiseError(logfile string, uuid string, errMsg string) {
  240. writeLog(logfile, "[error] ", errMsg)
  241. moveLogFile(logfile, "error", uuid)
  242. panic("ERROR. " + errMsg)
  243. }
  244. func ChmodR(path string) error {
  245. return filepath.Walk(path, func(name string, info os.FileInfo, err error) error {
  246. if err == nil {
  247. err = os.Chmod(name, 0755)
  248. }
  249. return err
  250. })
  251. }
  252. func main() {
  253. //Init the log folder if it doesn't exists
  254. if !file_exists("log/") {
  255. os.MkdirAll("log/", 0777)
  256. }
  257. if !file_exists("log/done/") {
  258. os.MkdirAll("log/done/", 0777)
  259. }
  260. if !file_exists("log/error/") {
  261. os.MkdirAll("log/error/", 0777)
  262. }
  263. //Check argument if satisfied
  264. if len(os.Args) < 3 {
  265. fmt.Println("<<ArOZ Online System File System Compress File Creator>>")
  266. fmt.Println("Usage: fszip {uuid} {command_in_base64_JSON}")
  267. fmt.Println("Command must be an array containing [{'zip' / 'unzip'},{filepath},{zip_target}]")
  268. return
  269. }
  270. startSettings := os.Args[1:]
  271. uuid := startSettings[0]
  272. encodedCommand := startSettings[1]
  273. decodedCommand := decodeBase64(encodedCommand)
  274. filename := uuid + ".log"
  275. logfile := "log/" + filename
  276. var command []string
  277. //Check if the given uuid already exists. If yes, terminate the execution
  278. if file_exists("log/"+uuid+".log") || file_exists("log/done/"+uuid+".log") || file_exists("log/error/"+uuid+".log") {
  279. panic("ERROR. Given uuid already exists.")
  280. }
  281. //Create the log file for this task
  282. writeLog(logfile, "[init] ", "Task created on "+getTimestamp())
  283. //Parse the JSON string into readable array
  284. err := json.Unmarshal([]byte(decodedCommand), &command)
  285. if err != nil {
  286. writeLog(logfile, "[error] ", "Unable to parse JSON string.")
  287. moveLogFile(logfile, "error", uuid)
  288. panic("ERROR. Unable to parse JSON string.")
  289. }
  290. //Check opr
  291. if command[0] == "zip" {
  292. //Start the compression process for the given path
  293. //Command structure: ["zip","{source}","{target} (Pass in empty string for default location)"]
  294. //Check if the given filepath exists
  295. if !file_exists(command[1]) {
  296. raiseError(logfile, uuid, "Source not exists.")
  297. }
  298. inpath := command[1]
  299. //Check if inpath end with "/". If yes, remove it
  300. if inpath[len(inpath)-1:] == "/" {
  301. inpath = inpath[0 : len(inpath)-1]
  302. }
  303. outpath := command[2]
  304. //File exists. Check if it is a folder or not.
  305. if outpath != "" {
  306. //If there is a defined export filepath, check if the parent dir exists. If not, create it
  307. if !file_exists(path.Dir(outpath)) {
  308. os.MkdirAll(path.Dir(outpath), 0755)
  309. }
  310. } else {
  311. //There is no defined export path. Export next to the source as zip.
  312. if isDir(command[1]) {
  313. outpath = path.Dir(path.Dir(inpath)) + "/" + path.Base(inpath) + ".zip"
  314. } else {
  315. outpath = path.Dir(inpath) + "/" + strings.TrimSuffix(inpath, filepath.Ext(inpath)) + ".zip"
  316. }
  317. }
  318. if file_exists(outpath) {
  319. raiseError(logfile, uuid, "Output file already exists.")
  320. }
  321. compress(inpath, outpath)
  322. os.Chmod(outpath, 0777)
  323. finishFileOperation(logfile, uuid)
  324. } else if command[0] == "unzip" {
  325. //Unzip a given filepath
  326. //command structure: ["unzip","{source}","{target}"]
  327. if !file_exists(command[1]) {
  328. raiseError(logfile, uuid, "Source not exists.")
  329. }
  330. inpath := command[1]
  331. outpath := command[2]
  332. if outpath == "" {
  333. //If unzup target is empty string, unzip to the current directory which the script is executed
  334. outpath = "./"
  335. }
  336. //Check if the input path is a zip file. If not, post a warning into the log file
  337. if filepath.Ext(inpath) != ".zip" {
  338. writeLog(logfile, "[warning] ", "The given file might not be a zip file. Trying to open it anyway. File ext given: "+filepath.Ext(inpath))
  339. }
  340. //Create outpath if it doesn't exists
  341. if !file_exists(outpath) {
  342. os.MkdirAll(outpath, 0755)
  343. }
  344. unzip(inpath, outpath)
  345. if isDir(outpath) {
  346. ChmodR(outpath)
  347. } else {
  348. os.Chmod(outpath, 0755)
  349. }
  350. finishFileOperation(logfile, uuid)
  351. }
  352. }