agi.file.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. package agi
  2. import (
  3. "errors"
  4. "io/ioutil"
  5. "log"
  6. "os"
  7. "path/filepath"
  8. "github.com/robertkrimen/otto"
  9. fs "imuslab.com/arozos/mod/filesystem"
  10. user "imuslab.com/arozos/mod/user"
  11. )
  12. /*
  13. AJGI File Processing Library
  14. This is a library for handling image related functionalities in agi scripts.
  15. By Alanyueng 2020 <- This person write shitty code that need me to tidy up (by tobychui)
  16. Complete rewrite by tobychui in Sept 2020
  17. */
  18. func (g *Gateway) FileLibRegister() {
  19. err := g.RegisterLib("filelib", g.injectFileLibFunctions)
  20. if err != nil {
  21. log.Fatal(err)
  22. }
  23. }
  24. func (g *Gateway) injectFileLibFunctions(vm *otto.Otto, u *user.User) {
  25. //Legacy File system API
  26. //writeFile(virtualFilepath, content) => return true/false when succeed / failed
  27. vm.Set("_filelib_writeFile", func(call otto.FunctionCall) otto.Value {
  28. vpath, err := call.Argument(0).ToString()
  29. if err != nil {
  30. g.raiseError(err)
  31. reply, _ := vm.ToValue(false)
  32. return reply
  33. }
  34. //Check for permission
  35. if !u.CanWrite(vpath) {
  36. panic(vm.MakeCustomError("PermissionDenied", "Path access denied: "+vpath))
  37. }
  38. content, err := call.Argument(1).ToString()
  39. if err != nil {
  40. g.raiseError(err)
  41. reply, _ := vm.ToValue(false)
  42. return reply
  43. }
  44. //Check if there is quota for the given length
  45. if !u.StorageQuota.HaveSpace(int64(len(content))) {
  46. //User have no remaining storage quota
  47. g.raiseError(errors.New("Storage Quota Fulled"))
  48. reply, _ := vm.ToValue(false)
  49. return reply
  50. }
  51. //Translate the virtual path to realpath
  52. rpath, err := virtualPathToRealPath(vpath, u)
  53. if err != nil {
  54. g.raiseError(err)
  55. reply, _ := vm.ToValue(false)
  56. return reply
  57. }
  58. //Check if file already exists.
  59. if fileExists(rpath) {
  60. //Check if this user own this file
  61. isOwner := u.IsOwnerOfFile(rpath)
  62. if isOwner {
  63. //This user own this system. Remove this file from his quota
  64. u.RemoveOwnershipFromFile(rpath)
  65. }
  66. }
  67. //Create and write to file using ioutil
  68. err = ioutil.WriteFile(rpath, []byte(content), 0755)
  69. if err != nil {
  70. g.raiseError(err)
  71. reply, _ := vm.ToValue(false)
  72. return reply
  73. }
  74. //Add the filesize to user quota
  75. u.SetOwnerOfFile(rpath)
  76. reply, _ := vm.ToValue(true)
  77. return reply
  78. })
  79. vm.Set("_filelib_deleteFile", func(call otto.FunctionCall) otto.Value {
  80. vpath, err := call.Argument(0).ToString()
  81. if err != nil {
  82. g.raiseError(err)
  83. reply, _ := vm.ToValue(false)
  84. return reply
  85. }
  86. //Check for permission
  87. if !u.CanWrite(vpath) {
  88. panic(vm.MakeCustomError("PermissionDenied", "Path access denied: "+vpath))
  89. }
  90. //Translate the virtual path to realpath
  91. rpath, err := virtualPathToRealPath(vpath, u)
  92. if err != nil {
  93. g.raiseError(err)
  94. reply, _ := vm.ToValue(false)
  95. return reply
  96. }
  97. //Check if file already exists.
  98. if fileExists(rpath) {
  99. //Check if this user own this file
  100. isOwner := u.IsOwnerOfFile(rpath)
  101. if isOwner {
  102. //This user own this system. Remove this file from his quota
  103. u.RemoveOwnershipFromFile(rpath)
  104. }
  105. } else {
  106. g.raiseError(errors.New("File not exists"))
  107. reply, _ := vm.ToValue(false)
  108. return reply
  109. }
  110. //Remove the file
  111. os.Remove(rpath)
  112. reply, _ := vm.ToValue(true)
  113. return reply
  114. })
  115. //readFile(virtualFilepath) => return content in string
  116. vm.Set("_filelib_readFile", func(call otto.FunctionCall) otto.Value {
  117. vpath, err := call.Argument(0).ToString()
  118. if err != nil {
  119. g.raiseError(err)
  120. reply, _ := vm.ToValue(false)
  121. return reply
  122. }
  123. //Check for permission
  124. if !u.CanRead(vpath) {
  125. panic(vm.MakeCustomError("PermissionDenied", "Path access denied: "+vpath))
  126. }
  127. //Translate the virtual path to realpath
  128. rpath, err := virtualPathToRealPath(vpath, u)
  129. if err != nil {
  130. g.raiseError(err)
  131. reply, _ := vm.ToValue(false)
  132. return reply
  133. }
  134. //Create and write to file using ioUtil
  135. content, err := ioutil.ReadFile(rpath)
  136. if err != nil {
  137. g.raiseError(err)
  138. reply, _ := vm.ToValue(false)
  139. return reply
  140. }
  141. reply, _ := vm.ToValue(string(content))
  142. return reply
  143. })
  144. //Listdir
  145. //readdir("user:/Desktop") => return filelist in array
  146. vm.Set("_filelib_readdir", func(call otto.FunctionCall) otto.Value {
  147. vpath, err := call.Argument(0).ToString()
  148. if err != nil {
  149. g.raiseError(err)
  150. reply, _ := vm.ToValue(false)
  151. return reply
  152. }
  153. //Translate the virtual path to realpath
  154. rpath, err := virtualPathToRealPath(vpath, u)
  155. if err != nil {
  156. g.raiseError(err)
  157. reply, _ := vm.ToValue(false)
  158. return reply
  159. }
  160. fileList, err := specialGlob(rpath)
  161. if err != nil {
  162. g.raiseError(err)
  163. reply, _ := vm.ToValue(false)
  164. return reply
  165. }
  166. //Translate all paths to virtual paths
  167. results := []string{}
  168. for _, file := range fileList {
  169. if IsDir(file) {
  170. thisRpath, _ := realpathToVirtualpath(file, u)
  171. results = append(results, thisRpath)
  172. }
  173. }
  174. reply, _ := vm.ToValue(results)
  175. return reply
  176. })
  177. //Usage
  178. //filelib.walk("user:/") => list everything recursively
  179. //filelib.walk("user:/", "folder") => list all folder recursively
  180. //filelib.walk("user:/", "file") => list all files recursively
  181. vm.Set("_filelib_walk", func(call otto.FunctionCall) otto.Value {
  182. vpath, err := call.Argument(0).ToString()
  183. if err != nil {
  184. g.raiseError(err)
  185. reply, _ := vm.ToValue(false)
  186. return reply
  187. }
  188. mode, err := call.Argument(1).ToString()
  189. if err != nil {
  190. mode = "all"
  191. }
  192. rpath, err := virtualPathToRealPath(vpath, u)
  193. if err != nil {
  194. g.raiseError(err)
  195. reply, _ := vm.ToValue(false)
  196. return reply
  197. }
  198. results := []string{}
  199. err = filepath.Walk(rpath, func(path string, info os.FileInfo, err error) error {
  200. thisVpath, err := realpathToVirtualpath(path, u)
  201. if mode == "file" {
  202. if !info.IsDir() {
  203. results = append(results, thisVpath)
  204. }
  205. } else if mode == "folder" {
  206. if info.IsDir() {
  207. results = append(results, thisVpath)
  208. }
  209. } else {
  210. results = append(results, thisVpath)
  211. }
  212. return nil
  213. })
  214. reply, _ := vm.ToValue(results)
  215. return reply
  216. })
  217. //Glob
  218. //glob("user:/Desktop/*.mp3") => return fileList in array
  219. //glob("/") => return a list of root directories
  220. vm.Set("_filelib_glob", func(call otto.FunctionCall) otto.Value {
  221. regex, err := call.Argument(0).ToString()
  222. if err != nil {
  223. g.raiseError(err)
  224. reply, _ := vm.ToValue(false)
  225. return reply
  226. }
  227. //Handle when regex = "." or "./" (listroot)
  228. if filepath.ToSlash(filepath.Clean(regex)) == "/" || filepath.Clean(regex) == "." {
  229. //List Root
  230. rootDirs := []string{}
  231. fileHandlers := u.GetAllFileSystemHandler()
  232. for _, fsh := range fileHandlers {
  233. rootDirs = append(rootDirs, fsh.UUID+":/")
  234. }
  235. reply, _ := vm.ToValue(rootDirs)
  236. return reply
  237. } else {
  238. //Check for permission
  239. if !u.CanRead(regex) {
  240. panic(vm.MakeCustomError("PermissionDenied", "Path access denied"))
  241. }
  242. //This function can only handle wildcard in filename but not in dir name
  243. vrootPath := filepath.Dir(regex)
  244. regexFilename := filepath.Base(regex)
  245. //Translate the virtual path to realpath
  246. rrootPath, err := virtualPathToRealPath(vrootPath, u)
  247. if err != nil {
  248. g.raiseError(err)
  249. reply, _ := vm.ToValue(false)
  250. return reply
  251. }
  252. suitableFiles, err := filepath.Glob(rrootPath + "/" + regexFilename)
  253. if err != nil {
  254. g.raiseError(err)
  255. reply, _ := vm.ToValue(false)
  256. return reply
  257. }
  258. results := []string{}
  259. for _, file := range suitableFiles {
  260. thisRpath, _ := realpathToVirtualpath(filepath.ToSlash(file), u)
  261. results = append(results, thisRpath)
  262. }
  263. reply, _ := vm.ToValue(results)
  264. return reply
  265. }
  266. })
  267. //Advance Glob using file system special Glob, cannot use to scan root dirs
  268. vm.Set("_filelib_aglob", func(call otto.FunctionCall) otto.Value {
  269. regex, err := call.Argument(0).ToString()
  270. if err != nil {
  271. g.raiseError(err)
  272. reply, _ := vm.ToValue(false)
  273. return reply
  274. }
  275. if regex != "/" && !u.CanRead(regex) {
  276. panic(vm.MakeCustomError("PermissionDenied", "Path access denied"))
  277. }
  278. //This function can only handle wildcard in filename but not in dir name
  279. vrootPath := filepath.Dir(regex)
  280. regexFilename := filepath.Base(regex)
  281. //Translate the virtual path to realpath
  282. rrootPath, err := virtualPathToRealPath(vrootPath, u)
  283. if err != nil {
  284. g.raiseError(err)
  285. reply, _ := vm.ToValue(false)
  286. return reply
  287. }
  288. suitableFiles, err := specialGlob(rrootPath + "/" + regexFilename)
  289. if err != nil {
  290. g.raiseError(err)
  291. reply, _ := vm.ToValue(false)
  292. return reply
  293. }
  294. results := []string{}
  295. for _, file := range suitableFiles {
  296. thisRpath, _ := realpathToVirtualpath(filepath.ToSlash(file), u)
  297. results = append(results, thisRpath)
  298. }
  299. reply, _ := vm.ToValue(results)
  300. return reply
  301. })
  302. //filesize("user:/Desktop/test.txt")
  303. vm.Set("_filelib_filesize", func(call otto.FunctionCall) otto.Value {
  304. vpath, err := call.Argument(0).ToString()
  305. if err != nil {
  306. g.raiseError(err)
  307. reply, _ := vm.ToValue(false)
  308. return reply
  309. }
  310. //Check for permission
  311. if !u.CanRead(vpath) {
  312. panic(vm.MakeCustomError("PermissionDenied", "Path access denied"))
  313. }
  314. //Translate the virtual path to realpath
  315. rpath, err := virtualPathToRealPath(vpath, u)
  316. if err != nil {
  317. g.raiseError(err)
  318. reply, _ := vm.ToValue(false)
  319. return reply
  320. }
  321. //Get filesize of file
  322. rawsize := fs.GetFileSize(rpath)
  323. if err != nil {
  324. g.raiseError(err)
  325. reply, _ := vm.ToValue(false)
  326. return reply
  327. }
  328. reply, _ := vm.ToValue(rawsize)
  329. return reply
  330. })
  331. //fileExists("user:/Desktop/test.txt") => return true / false
  332. vm.Set("_filelib_fileExists", func(call otto.FunctionCall) otto.Value {
  333. vpath, err := call.Argument(0).ToString()
  334. if err != nil {
  335. g.raiseError(err)
  336. reply, _ := vm.ToValue(false)
  337. return reply
  338. }
  339. //Check for permission
  340. if !u.CanRead(vpath) {
  341. panic(vm.MakeCustomError("PermissionDenied", "Path access denied"))
  342. }
  343. //Translate the virtual path to realpath
  344. rpath, err := virtualPathToRealPath(vpath, u)
  345. if err != nil {
  346. g.raiseError(err)
  347. reply, _ := vm.ToValue(false)
  348. return reply
  349. }
  350. if fileExists(rpath) {
  351. reply, _ := vm.ToValue(true)
  352. return reply
  353. } else {
  354. reply, _ := vm.ToValue(false)
  355. return reply
  356. }
  357. })
  358. //fileExists("user:/Desktop/test.txt") => return true / false
  359. vm.Set("_filelib_isDir", func(call otto.FunctionCall) otto.Value {
  360. vpath, err := call.Argument(0).ToString()
  361. if err != nil {
  362. g.raiseError(err)
  363. reply, _ := vm.ToValue(false)
  364. return reply
  365. }
  366. //Check for permission
  367. if !u.CanRead(vpath) {
  368. panic(vm.MakeCustomError("PermissionDenied", "Path access denied: "+vpath))
  369. }
  370. //Translate the virtual path to realpath
  371. rpath, err := virtualPathToRealPath(vpath, u)
  372. if err != nil {
  373. g.raiseError(err)
  374. reply, _ := vm.ToValue(false)
  375. return reply
  376. }
  377. if _, err := os.Stat(rpath); os.IsNotExist(err) {
  378. //File not exists
  379. panic(vm.MakeCustomError("File Not Exists", "Required path not exists"))
  380. }
  381. if IsDir(rpath) {
  382. reply, _ := vm.ToValue(true)
  383. return reply
  384. } else {
  385. reply, _ := vm.ToValue(false)
  386. return reply
  387. }
  388. })
  389. //Make directory command
  390. vm.Set("_filelib_mkdir", func(call otto.FunctionCall) otto.Value {
  391. vdir, err := call.Argument(0).ToString()
  392. if err != nil {
  393. return otto.FalseValue()
  394. }
  395. //Check for permission
  396. if !u.CanWrite(vdir) {
  397. panic(vm.MakeCustomError("PermissionDenied", "Path access denied"))
  398. }
  399. //Translate the path to realpath
  400. rdir, err := virtualPathToRealPath(vdir, u)
  401. if err != nil {
  402. log.Println(err.Error())
  403. return otto.FalseValue()
  404. }
  405. //Create the directory at rdir location
  406. err = os.MkdirAll(rdir, 0755)
  407. if err != nil {
  408. log.Println(err.Error())
  409. return otto.FalseValue()
  410. }
  411. return otto.TrueValue()
  412. })
  413. //Get MD5 of the given filepath
  414. vm.Set("_filelib_md5", func(call otto.FunctionCall) otto.Value {
  415. log.Println("Call to MD5 Functions!")
  416. return otto.FalseValue()
  417. })
  418. //Get the root name of the given virtual path root
  419. vm.Set("_filelib_rname", func(call otto.FunctionCall) otto.Value {
  420. //Get virtual path from the function input
  421. vpath, err := call.Argument(0).ToString()
  422. if err != nil {
  423. g.raiseError(err)
  424. return otto.FalseValue()
  425. }
  426. //Get fs handler from the vpath
  427. fsHandler, err := u.GetFileSystemHandlerFromVirtualPath(vpath)
  428. if err != nil {
  429. g.raiseError(err)
  430. return otto.FalseValue()
  431. }
  432. //Return the name of the fsHandler
  433. name, _ := vm.ToValue(fsHandler.Name)
  434. return name
  435. })
  436. vm.Set("_filelib_mtime", func(call otto.FunctionCall) otto.Value {
  437. vpath, err := call.Argument(0).ToString()
  438. if err != nil {
  439. g.raiseError(err)
  440. reply, _ := vm.ToValue(false)
  441. return reply
  442. }
  443. //Check for permission
  444. if !u.CanRead(vpath) {
  445. panic(vm.MakeCustomError("PermissionDenied", "Path access denied"))
  446. }
  447. parseToUnix, err := call.Argument(1).ToBoolean()
  448. if err != nil {
  449. parseToUnix = false
  450. }
  451. rpath, err := virtualPathToRealPath(vpath, u)
  452. if err != nil {
  453. log.Println(err.Error())
  454. return otto.FalseValue()
  455. }
  456. info, err := os.Stat(rpath)
  457. if err != nil {
  458. log.Println(err.Error())
  459. return otto.FalseValue()
  460. }
  461. modTime := info.ModTime()
  462. if parseToUnix {
  463. result, _ := otto.ToValue(modTime.Unix())
  464. return result
  465. } else {
  466. result, _ := otto.ToValue(modTime.Format("2006-01-02 15:04:05"))
  467. return result
  468. }
  469. })
  470. /*
  471. vm.Set("_filelib_decodeURI", func(call otto.FunctionCall) otto.Value {
  472. originalURI, err := call.Argument(0).ToString()
  473. if err != nil {
  474. g.raiseError(err)
  475. reply, _ := vm.ToValue(false)
  476. return reply
  477. }
  478. decodedURI := specialURIDecode(originalURI)
  479. result, err := otto.ToValue(decodedURI)
  480. if err != nil {
  481. g.raiseError(err)
  482. reply, _ := vm.ToValue(false)
  483. return reply
  484. }
  485. return result
  486. })
  487. */
  488. //Other file operations, wip
  489. //Wrap all the native code function into an imagelib class
  490. vm.Run(`
  491. var filelib = {};
  492. filelib.writeFile = _filelib_writeFile;
  493. filelib.readFile = _filelib_readFile;
  494. filelib.deleteFile = _filelib_deleteFile;
  495. filelib.readdir = _filelib_readdir;
  496. filelib.walk = _filelib_walk;
  497. filelib.glob = _filelib_glob;
  498. filelib.aglob = _filelib_aglob;
  499. filelib.filesize = _filelib_filesize;
  500. filelib.fileExists = _filelib_fileExists;
  501. filelib.isDir = _filelib_isDir;
  502. filelib.md5 = _filelib_md5;
  503. filelib.mkdir = _filelib_mkdir;
  504. filelib.mtime = _filelib_mtime;
  505. filelib.rname = _filelib_rname;
  506. `)
  507. }