file_system.go 67 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447
  1. package main
  2. import (
  3. "crypto/sha256"
  4. "encoding/hex"
  5. "encoding/json"
  6. "errors"
  7. "io"
  8. "io/ioutil"
  9. "log"
  10. "math"
  11. "mime/multipart"
  12. "net/http"
  13. "net/url"
  14. "os"
  15. "path/filepath"
  16. "runtime"
  17. "sort"
  18. "strconv"
  19. "strings"
  20. "time"
  21. "github.com/gorilla/websocket"
  22. uuid "github.com/satori/go.uuid"
  23. fs "imuslab.com/arozos/mod/filesystem"
  24. fsp "imuslab.com/arozos/mod/filesystem/fspermission"
  25. hidden "imuslab.com/arozos/mod/filesystem/hidden"
  26. metadata "imuslab.com/arozos/mod/filesystem/metadata"
  27. module "imuslab.com/arozos/mod/modules"
  28. prout "imuslab.com/arozos/mod/prouter"
  29. "imuslab.com/arozos/mod/share"
  30. storage "imuslab.com/arozos/mod/storage"
  31. user "imuslab.com/arozos/mod/user"
  32. )
  33. var (
  34. thumbRenderHandler *metadata.RenderHandler
  35. shareManager *share.Manager
  36. )
  37. type trashedFile struct {
  38. Filename string
  39. Filepath string
  40. FileExt string
  41. IsDir bool
  42. Filesize int64
  43. RemoveTimestamp int64
  44. RemoveDate string
  45. OriginalPath string
  46. OriginalFilename string
  47. }
  48. func FileSystemInit() {
  49. router := prout.NewModuleRouter(prout.RouterOption{
  50. ModuleName: "File Manager",
  51. AdminOnly: false,
  52. UserHandler: userHandler,
  53. DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
  54. sendErrorResponse(w, "Permission Denied")
  55. },
  56. })
  57. //Upload related functions
  58. router.HandleFunc("/system/file_system/upload", system_fs_handleUpload)
  59. router.HandleFunc("/system/file_system/lowmemUpload", system_fs_handleLowMemoryUpload)
  60. //Other file operations
  61. router.HandleFunc("/system/file_system/validateFileOpr", system_fs_validateFileOpr)
  62. router.HandleFunc("/system/file_system/fileOpr", system_fs_handleOpr)
  63. router.HandleFunc("/system/file_system/ws/fileOpr", system_fs_handleWebSocketOpr)
  64. router.HandleFunc("/system/file_system/listDir", system_fs_handleList)
  65. router.HandleFunc("/system/file_system/listDirHash", system_fs_handleDirHash)
  66. router.HandleFunc("/system/file_system/listRoots", system_fs_listRoot)
  67. router.HandleFunc("/system/file_system/listDrives", system_fs_listDrives)
  68. router.HandleFunc("/system/file_system/newItem", system_fs_handleNewObjects)
  69. router.HandleFunc("/system/file_system/preference", system_fs_handleUserPreference)
  70. router.HandleFunc("/system/file_system/listTrash", system_fs_scanTrashBin)
  71. router.HandleFunc("/system/file_system/ws/listTrash", system_fs_WebSocketScanTrashBin)
  72. router.HandleFunc("/system/file_system/clearTrash", system_fs_clearTrashBin)
  73. router.HandleFunc("/system/file_system/restoreTrash", system_fs_restoreFile)
  74. router.HandleFunc("/system/file_system/zipHandler", system_fs_zipHandler)
  75. router.HandleFunc("/system/file_system/getProperties", system_fs_getFileProperties)
  76. router.HandleFunc("/system/file_system/pathTranslate", system_fs_handlePathTranslate)
  77. router.HandleFunc("/system/file_system/handleFilePermission", system_fs_handleFilePermission)
  78. router.HandleFunc("/system/file_system/search", system_fs_handleFileSearch)
  79. //Thumbnail caching functions
  80. router.HandleFunc("/system/file_system/handleFolderCache", system_fs_handleFolderCache)
  81. router.HandleFunc("/system/file_system/handleCacheRender", system_fs_handleCacheRender)
  82. //Register the module
  83. moduleHandler.RegisterModule(module.ModuleInfo{
  84. Name: "File Manager",
  85. Group: "System Tools",
  86. IconPath: "SystemAO/file_system/img/small_icon.png",
  87. Version: "1.0",
  88. StartDir: "SystemAO/file_system/file_explorer.html",
  89. SupportFW: true,
  90. InitFWSize: []int{1080, 580},
  91. LaunchFWDir: "SystemAO/file_system/file_explorer.html",
  92. SupportEmb: false,
  93. })
  94. //Register the Trashbin module
  95. moduleHandler.RegisterModule(module.ModuleInfo{
  96. Name: "Trash Bin",
  97. Group: "System Tools",
  98. IconPath: "SystemAO/file_system/trashbin_img/small_icon.png",
  99. Version: "1.0",
  100. StartDir: "SystemAO/file_system/trashbin.html",
  101. SupportFW: true,
  102. InitFWSize: []int{1080, 580},
  103. LaunchFWDir: "SystemAO/file_system/trashbin.html",
  104. SupportEmb: false,
  105. SupportedExt: []string{"*"},
  106. })
  107. //Register the Zip Extractor module
  108. moduleHandler.RegisterModule(module.ModuleInfo{
  109. Name: "Zip Extractor",
  110. Group: "System Tools",
  111. IconPath: "SystemAO/file_system/img/zip_extractor.png",
  112. Version: "1.0",
  113. SupportFW: false,
  114. LaunchEmb: "SystemAO/file_system/zip_extractor.html",
  115. SupportEmb: true,
  116. InitEmbSize: []int{260, 120},
  117. SupportedExt: []string{".zip"},
  118. })
  119. //Create user root if not exists
  120. err := os.MkdirAll(*root_directory+"users/", 0755)
  121. if err != nil {
  122. log.Println("Failed to create system storage root.")
  123. panic(err)
  124. }
  125. //Create database table if not exists
  126. err = sysdb.NewTable("fs")
  127. if err != nil {
  128. log.Println("Failed to create table for file system")
  129. panic(err)
  130. }
  131. //Create a RenderHandler for caching thumbnails
  132. thumbRenderHandler = metadata.NewRenderHandler()
  133. /*
  134. Share Related Registering
  135. This section of functions create and register the file share service
  136. for the arozos
  137. */
  138. //Create a share manager to handle user file sharae
  139. shareManager = share.NewShareManager(share.Options{
  140. AuthAgent: authAgent,
  141. Database: sysdb,
  142. UserHandler: userHandler,
  143. HostName: *host_name,
  144. TmpFolder: *tmp_directory,
  145. })
  146. //Share related functions
  147. router.HandleFunc("/system/file_system/share/new", shareManager.HandleCreateNewShare)
  148. router.HandleFunc("/system/file_system/share/delete", shareManager.HandleDeleteShare)
  149. router.HandleFunc("/system/file_system/share/edit", shareManager.HandleEditShare)
  150. //Handle the main share function
  151. http.HandleFunc("/share", shareManager.HandleShareAccess)
  152. /*
  153. Nighly Tasks
  154. These functions allow file system to clear and maintain
  155. the arozos file system when no one is using the system
  156. */
  157. //Clear tmp folder if files is placed here too long
  158. RegisterNightlyTask(system_fs_clearOldTmpFiles)
  159. //Clear shares that its parent file no longer exists in the system
  160. shareManager.ValidateAndClearShares()
  161. RegisterNightlyTask(shareManager.ValidateAndClearShares)
  162. }
  163. /*
  164. File Search
  165. Handle file search in wildcard and recursive search
  166. */
  167. func system_fs_handleFileSearch(w http.ResponseWriter, r *http.Request) {
  168. //Get the user information
  169. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  170. if err != nil {
  171. sendErrorResponse(w, "User not logged in")
  172. return
  173. }
  174. //Get the search target root path
  175. vpath, err := mv(r, "path", true)
  176. if err != nil {
  177. sendErrorResponse(w, "Invalid vpath given")
  178. return
  179. }
  180. keyword, err := mv(r, "keyword", true)
  181. if err != nil {
  182. sendErrorResponse(w, "Invalid keyword given")
  183. return
  184. }
  185. //Translate the vpath to realpath
  186. rpath, err := userinfo.VirtualPathToRealPath(vpath)
  187. if err != nil {
  188. sendErrorResponse(w, "Invalid path given")
  189. return
  190. }
  191. //Check if the search mode is recursive keyword or wildcard
  192. if len(keyword) > 1 && keyword[:1] == "/" {
  193. //Wildcard
  194. wildcard := keyword[1:]
  195. matchingFiles, err := filepath.Glob(filepath.Join(rpath, wildcard))
  196. if err != nil {
  197. sendErrorResponse(w, err.Error())
  198. return
  199. }
  200. //Prepare result struct
  201. results := []fs.FileData{}
  202. //Process the matching files. Do not allow directory escape
  203. srcAbs, _ := filepath.Abs(rpath)
  204. srcAbs = filepath.ToSlash(srcAbs)
  205. escaped := false
  206. for _, matchedFile := range matchingFiles {
  207. absMatch, _ := filepath.Abs(matchedFile)
  208. absMatch = filepath.ToSlash(absMatch)
  209. if !strings.Contains(absMatch, srcAbs) {
  210. escaped = true
  211. }
  212. thisVpath, _ := userinfo.RealPathToVirtualPath(matchedFile)
  213. results = append(results, fs.GetFileDataFromPath(thisVpath, matchedFile, 2))
  214. }
  215. if escaped {
  216. sendErrorResponse(w, "Search keywords contain escape character!")
  217. return
  218. }
  219. //OK. Tidy up the results
  220. js, _ := json.Marshal(results)
  221. sendJSONResponse(w, string(js))
  222. } else {
  223. //Recursive keyword
  224. results := []fs.FileData{}
  225. err := filepath.Walk(rpath, func(path string, info os.FileInfo, err error) error {
  226. if strings.Contains(filepath.Base(path), keyword) {
  227. //This is a matching file
  228. if !fs.IsInsideHiddenFolder(path) {
  229. thisVpath, _ := userinfo.RealPathToVirtualPath(path)
  230. results = append(results, fs.GetFileDataFromPath(thisVpath, path, 2))
  231. }
  232. }
  233. return nil
  234. })
  235. if err != nil {
  236. sendErrorResponse(w, err.Error())
  237. return
  238. }
  239. //OK. Tidy up the results
  240. js, _ := json.Marshal(results)
  241. sendJSONResponse(w, string(js))
  242. }
  243. }
  244. /*
  245. Handle low-memory upload operations
  246. This function is specailly designed to work with low memory devices
  247. (e.g. ZeroPi / Orange Pi Zero with 512MB RAM)
  248. */
  249. func system_fs_handleLowMemoryUpload(w http.ResponseWriter, r *http.Request) {
  250. //Get user info
  251. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  252. if err != nil {
  253. w.WriteHeader(http.StatusUnauthorized)
  254. w.Write([]byte("401 - Unauthorized"))
  255. return
  256. }
  257. //Get filename and upload path
  258. filename, err := mv(r, "filename", false)
  259. if filename == "" || err != nil {
  260. w.WriteHeader(http.StatusInternalServerError)
  261. w.Write([]byte("500 - Invalid filename given"))
  262. return
  263. }
  264. //Get upload target directory
  265. uploadTarget, err := mv(r, "path", false)
  266. if uploadTarget == "" || err != nil {
  267. w.WriteHeader(http.StatusInternalServerError)
  268. w.Write([]byte("500 - Invalid path given"))
  269. return
  270. }
  271. //Check if the user can write to this folder
  272. if !userinfo.CanWrite(uploadTarget) {
  273. //No permission
  274. w.WriteHeader(http.StatusForbidden)
  275. w.Write([]byte("403 - Access Denied"))
  276. return
  277. }
  278. //Translate the upload target directory
  279. realUploadPath, err := userinfo.VirtualPathToRealPath(uploadTarget)
  280. if err != nil {
  281. w.WriteHeader(http.StatusInternalServerError)
  282. w.Write([]byte("500 - Path translation failed"))
  283. return
  284. }
  285. //Generate an UUID for this upload
  286. uploadUUID := uuid.NewV4().String()
  287. uploadFolder := filepath.Join(*tmp_directory, "uploads", uploadUUID)
  288. os.MkdirAll(uploadFolder, 0700)
  289. targetUploadLocation := filepath.Join(realUploadPath, filename)
  290. if !fileExists(realUploadPath) {
  291. os.MkdirAll(realUploadPath, 0755)
  292. }
  293. //Start websocket connection
  294. var upgrader = websocket.Upgrader{}
  295. c, err := upgrader.Upgrade(w, r, nil)
  296. defer c.Close()
  297. //Handle WebSocket upload
  298. blockCounter := 0
  299. chunkName := []string{}
  300. lastChunkArrivalTime := time.Now().Unix()
  301. //Setup a timeout listener, check if connection still active every 1 minute
  302. ticker := time.NewTicker(60 * time.Second)
  303. done := make(chan bool)
  304. go func() {
  305. for {
  306. select {
  307. case <-done:
  308. return
  309. case <-ticker.C:
  310. if time.Now().Unix()-lastChunkArrivalTime > 300 {
  311. //Already 5 minutes without new data arraival. Stop connection
  312. log.Println("Upload WebSocket connection timeout. Disconnecting.")
  313. c.WriteControl(8, []byte{}, time.Now().Add(time.Second))
  314. time.Sleep(1 * time.Second)
  315. c.Close()
  316. return
  317. }
  318. }
  319. }
  320. }()
  321. totalFileSize := int64(0)
  322. for {
  323. mt, message, err := c.ReadMessage()
  324. if err != nil {
  325. //Connection closed by client. Clear the tmp folder and exit
  326. log.Println("Upload terminated by client. Cleaning tmp folder.")
  327. //Clear the tmp folder
  328. time.Sleep(1 * time.Second)
  329. os.RemoveAll(uploadFolder)
  330. return
  331. }
  332. //The mt should be 2 = binary for file upload and 1 for control syntax
  333. if mt == 1 {
  334. msg := strings.TrimSpace(string(message))
  335. if msg == "done" {
  336. //Start the merging process
  337. log.Println(userinfo.Username + " uploaded a file: " + filepath.Base(targetUploadLocation))
  338. break
  339. } else {
  340. //Unknown operations
  341. }
  342. } else if mt == 2 {
  343. //File block. Save it to tmp folder
  344. chunkFilepath := filepath.Join(uploadFolder, "upld_"+strconv.Itoa(blockCounter))
  345. chunkName = append(chunkName, chunkFilepath)
  346. ioutil.WriteFile(chunkFilepath, message, 0700)
  347. //Update the last upload chunk time
  348. lastChunkArrivalTime = time.Now().Unix()
  349. //Check if the file size is too big
  350. totalFileSize += fs.GetFileSize(chunkFilepath)
  351. if totalFileSize > max_upload_size {
  352. //File too big
  353. c.WriteMessage(1, []byte(`{\"error\":\"File size too large.\"}`))
  354. //Close the connection
  355. c.WriteControl(8, []byte{}, time.Now().Add(time.Second))
  356. time.Sleep(1 * time.Second)
  357. c.Close()
  358. //Clear the tmp files
  359. os.RemoveAll(uploadFolder)
  360. return
  361. }
  362. blockCounter++
  363. //Request client to send the next chunk
  364. c.WriteMessage(1, []byte("next"))
  365. }
  366. //log.Println("recv:", len(message), "type", mt)
  367. }
  368. //Merge the file
  369. out, err := os.OpenFile(targetUploadLocation, os.O_CREATE|os.O_WRONLY, 0755)
  370. if err != nil {
  371. log.Println("Failed to open file:", err)
  372. c.WriteMessage(1, []byte(`{\"error\":\"Failed to open destination file\"}`))
  373. c.WriteControl(8, []byte{}, time.Now().Add(time.Second))
  374. time.Sleep(1 * time.Second)
  375. c.Close()
  376. return
  377. }
  378. defer out.Close()
  379. for _, filesrc := range chunkName {
  380. srcChunkReader, err := os.Open(filesrc)
  381. if err != nil {
  382. log.Println("Failed to open Source Chunk", filesrc, " with error ", err.Error())
  383. c.WriteMessage(1, []byte(`{\"error\":\"Failed to open Source Chunk\"}`))
  384. return
  385. }
  386. io.Copy(out, srcChunkReader)
  387. srcChunkReader.Close()
  388. }
  389. //Set owner of the new uploaded file
  390. userinfo.SetOwnerOfFile(targetUploadLocation)
  391. //Return complete signal
  392. c.WriteMessage(1, []byte("OK"))
  393. //Stop the timeout listner
  394. done <- true
  395. //Clear the tmp folder
  396. time.Sleep(1 * time.Second)
  397. err = os.RemoveAll(uploadFolder)
  398. if err != nil {
  399. log.Println(err)
  400. }
  401. //Close WebSocket connection after finished
  402. c.WriteControl(8, []byte{}, time.Now().Add(time.Second))
  403. time.Sleep(1 * time.Second)
  404. c.Close()
  405. }
  406. /*
  407. Handle FORM POST based upload
  408. This function is design for general SBCs or computers with more than 1GB of RAM
  409. (e.g. Raspberry Pi 4 / Linux Server)
  410. */
  411. func system_fs_handleUpload(w http.ResponseWriter, r *http.Request) {
  412. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  413. if err != nil {
  414. sendErrorResponse(w, "User not logged in")
  415. return
  416. }
  417. username := userinfo.Username
  418. //Limit the max upload size to the user defined size
  419. if max_upload_size != 0 {
  420. r.Body = http.MaxBytesReader(w, r.Body, max_upload_size)
  421. }
  422. //Check if this is running under demo mode. If yes, reject upload
  423. if *demo_mode {
  424. sendErrorResponse(w, "You cannot upload in demo mode")
  425. return
  426. }
  427. err = r.ParseMultipartForm(int64(*upload_buf) << 20)
  428. if err != nil {
  429. //Filesize too big
  430. log.Println(err)
  431. sendErrorResponse(w, "File too large")
  432. return
  433. }
  434. file, handler, err := r.FormFile("file")
  435. if err != nil {
  436. log.Println("Error Retrieving File from upload by user: " + username)
  437. sendErrorResponse(w, "Unable to parse file from upload")
  438. return
  439. }
  440. //Get upload target directory
  441. uploadTarget, _ := mv(r, "path", true)
  442. if uploadTarget == "" {
  443. sendErrorResponse(w, "Upload target cannot be empty.")
  444. return
  445. }
  446. //Translate the upload target directory
  447. realUploadPath, err := userinfo.VirtualPathToRealPath(uploadTarget)
  448. if err != nil {
  449. sendErrorResponse(w, "Upload target is invalid or permission denied.")
  450. return
  451. }
  452. storeFilename := handler.Filename //Filename of the uploaded file
  453. destFilepath := filepath.ToSlash(filepath.Clean(realUploadPath)) + "/" + storeFilename
  454. if !fileExists(filepath.Dir(destFilepath)) {
  455. os.MkdirAll(filepath.Dir(destFilepath), 0755)
  456. }
  457. //Check if the upload target is read only.
  458. accmode := userinfo.GetPathAccessPermission(uploadTarget)
  459. if accmode == "readonly" {
  460. sendErrorResponse(w, "The upload target is Read Only.")
  461. return
  462. } else if accmode == "denied" {
  463. sendErrorResponse(w, "Access Denied")
  464. return
  465. }
  466. //Check for storage quota
  467. uploadFileSize := handler.Size
  468. if !userinfo.StorageQuota.HaveSpace(uploadFileSize) {
  469. sendErrorResponse(w, "Storage Quota Full")
  470. return
  471. }
  472. //Prepare the file to be created (uploaded)
  473. destination, err := os.Create(destFilepath)
  474. if err != nil {
  475. sendErrorResponse(w, err.Error())
  476. return
  477. }
  478. defer destination.Close()
  479. defer file.Close()
  480. //Move the file to destination file location
  481. if *enable_asyncFileUpload {
  482. //Use Async upload method
  483. go func(r *http.Request, file multipart.File, destination *os.File, userinfo *user.User) {
  484. //Do the file copying using a buffered reader
  485. buf := make([]byte, *file_opr_buff)
  486. for {
  487. n, err := file.Read(buf)
  488. if err != nil && err != io.EOF {
  489. log.Println(err.Error())
  490. return
  491. }
  492. if n == 0 {
  493. break
  494. }
  495. if _, err := destination.Write(buf[:n]); err != nil {
  496. log.Println(err.Error())
  497. return
  498. }
  499. }
  500. //Clear up buffered files
  501. r.MultipartForm.RemoveAll()
  502. //Set the ownership of file
  503. userinfo.SetOwnerOfFile(destFilepath)
  504. //Perform a GC afterward
  505. runtime.GC()
  506. }(r, file, destination, userinfo)
  507. } else {
  508. //Use blocking upload and move method
  509. buf := make([]byte, *file_opr_buff)
  510. for {
  511. n, err := file.Read(buf)
  512. if err != nil && err != io.EOF {
  513. log.Println(err.Error())
  514. return
  515. }
  516. if n == 0 {
  517. break
  518. }
  519. if _, err := destination.Write(buf[:n]); err != nil {
  520. log.Println(err.Error())
  521. return
  522. }
  523. }
  524. //Clear up buffered files
  525. r.MultipartForm.RemoveAll()
  526. //Set the ownership of file
  527. userinfo.SetOwnerOfFile(destFilepath)
  528. }
  529. //Finish up the upload
  530. //fmt.Printf("Uploaded File: %+v\n", handler.Filename)
  531. //fmt.Printf("File Size: %+v\n", handler.Size)
  532. //fmt.Printf("MIME Header: %+v\n", handler.Header)
  533. //fmt.Println("Upload target: " + realUploadPath)
  534. //Fnish upload. Fix the tmp filename
  535. log.Println(username + " uploaded a file: " + handler.Filename)
  536. //Do upload finishing stuff
  537. //Perform a GC
  538. runtime.GC()
  539. //Completed
  540. sendOK(w)
  541. return
  542. }
  543. //Validate if the copy and target process will involve file overwriting problem.
  544. func system_fs_validateFileOpr(w http.ResponseWriter, r *http.Request) {
  545. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  546. if err != nil {
  547. sendErrorResponse(w, err.Error())
  548. return
  549. }
  550. vsrcFiles, _ := mv(r, "src", true)
  551. vdestFile, _ := mv(r, "dest", true)
  552. var duplicateFiles []string
  553. //Loop through all files are see if there are duplication during copy and paste
  554. sourceFiles := []string{}
  555. decodedSourceFiles, _ := url.QueryUnescape(vsrcFiles)
  556. err = json.Unmarshal([]byte(decodedSourceFiles), &sourceFiles)
  557. if err != nil {
  558. sendErrorResponse(w, "Source file JSON parse error.")
  559. return
  560. }
  561. rdestFile, _ := userinfo.VirtualPathToRealPath(vdestFile)
  562. for _, file := range sourceFiles {
  563. rsrcFile, _ := userinfo.VirtualPathToRealPath(string(file))
  564. if fileExists(rdestFile + filepath.Base(rsrcFile)) {
  565. //File exists already.
  566. vpath, _ := userinfo.RealPathToVirtualPath(rsrcFile)
  567. duplicateFiles = append(duplicateFiles, vpath)
  568. }
  569. }
  570. jsonString, _ := json.Marshal(duplicateFiles)
  571. sendJSONResponse(w, string(jsonString))
  572. return
  573. }
  574. //Scan all directory and get trash file and send back results with WebSocket
  575. func system_fs_WebSocketScanTrashBin(w http.ResponseWriter, r *http.Request) {
  576. //Get and check user permission
  577. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  578. if err != nil {
  579. sendErrorResponse(w, "User not logged in")
  580. return
  581. }
  582. //Upgrade to websocket
  583. var upgrader = websocket.Upgrader{}
  584. c, err := upgrader.Upgrade(w, r, nil)
  585. if err != nil {
  586. w.WriteHeader(http.StatusInternalServerError)
  587. w.Write([]byte("500 - " + err.Error()))
  588. log.Print("Websocket Upgrade Error:", err.Error())
  589. return
  590. }
  591. //Start Scanning
  592. scanningRoots := []string{}
  593. //Get all roots to scan
  594. for _, storage := range userinfo.GetAllFileSystemHandler() {
  595. storageRoot := storage.Path
  596. scanningRoots = append(scanningRoots, storageRoot)
  597. }
  598. for _, rootPath := range scanningRoots {
  599. err := filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error {
  600. oneLevelUpper := filepath.Base(filepath.Dir(path))
  601. if oneLevelUpper == ".trash" {
  602. //This is a trashbin dir.
  603. file := path
  604. //Parse the trashFile struct
  605. timestamp := filepath.Ext(file)[1:]
  606. originalName := strings.TrimSuffix(filepath.Base(file), filepath.Ext(filepath.Base(file)))
  607. originalExt := filepath.Ext(filepath.Base(originalName))
  608. virtualFilepath, _ := userinfo.RealPathToVirtualPath(file)
  609. virtualOrgPath, _ := userinfo.RealPathToVirtualPath(filepath.Dir(filepath.Dir(file)))
  610. rawsize := fs.GetFileSize(file)
  611. timestampInt64, _ := StringToInt64(timestamp)
  612. removeTimeDate := time.Unix(timestampInt64, 0)
  613. if IsDir(file) {
  614. originalExt = ""
  615. }
  616. thisTrashFileObject := trashedFile{
  617. Filename: filepath.Base(file),
  618. Filepath: virtualFilepath,
  619. FileExt: originalExt,
  620. IsDir: IsDir(file),
  621. Filesize: int64(rawsize),
  622. RemoveTimestamp: timestampInt64,
  623. RemoveDate: timeToString(removeTimeDate),
  624. OriginalPath: virtualOrgPath,
  625. OriginalFilename: originalName,
  626. }
  627. //Send out the result as JSON string
  628. js, _ := json.Marshal(thisTrashFileObject)
  629. err := c.WriteMessage(1, js)
  630. if err != nil {
  631. //Connection already closed
  632. return err
  633. }
  634. }
  635. return nil
  636. })
  637. if err != nil {
  638. //Scan or client connection error (Connection closed?)
  639. return
  640. }
  641. }
  642. //Close connection after finished
  643. c.Close()
  644. }
  645. //Scan all the directory and get trash files within the system
  646. func system_fs_scanTrashBin(w http.ResponseWriter, r *http.Request) {
  647. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  648. if err != nil {
  649. sendErrorResponse(w, err.Error())
  650. return
  651. }
  652. username := userinfo.Username
  653. results := []trashedFile{}
  654. files, err := system_fs_listTrash(username)
  655. if err != nil {
  656. sendErrorResponse(w, err.Error())
  657. return
  658. }
  659. //Get information of each files and process it into results
  660. for _, file := range files {
  661. timestamp := filepath.Ext(file)[1:]
  662. originalName := strings.TrimSuffix(filepath.Base(file), filepath.Ext(filepath.Base(file)))
  663. originalExt := filepath.Ext(filepath.Base(originalName))
  664. virtualFilepath, _ := userinfo.RealPathToVirtualPath(file)
  665. virtualOrgPath, _ := userinfo.RealPathToVirtualPath(filepath.Dir(filepath.Dir(file)))
  666. rawsize := fs.GetFileSize(file)
  667. timestampInt64, _ := StringToInt64(timestamp)
  668. removeTimeDate := time.Unix(timestampInt64, 0)
  669. if IsDir(file) {
  670. originalExt = ""
  671. }
  672. results = append(results, trashedFile{
  673. Filename: filepath.Base(file),
  674. Filepath: virtualFilepath,
  675. FileExt: originalExt,
  676. IsDir: IsDir(file),
  677. Filesize: int64(rawsize),
  678. RemoveTimestamp: timestampInt64,
  679. RemoveDate: timeToString(removeTimeDate),
  680. OriginalPath: virtualOrgPath,
  681. OriginalFilename: originalName,
  682. })
  683. }
  684. //Sort the results by date, latest on top
  685. sort.Slice(results[:], func(i, j int) bool {
  686. return results[i].RemoveTimestamp > results[j].RemoveTimestamp
  687. })
  688. //Format and return the json results
  689. jsonString, _ := json.Marshal(results)
  690. sendJSONResponse(w, string(jsonString))
  691. }
  692. //Restore a trashed file to its parent dir
  693. func system_fs_restoreFile(w http.ResponseWriter, r *http.Request) {
  694. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  695. if err != nil {
  696. sendErrorResponse(w, err.Error())
  697. return
  698. }
  699. targetTrashedFile, err := mv(r, "src", true)
  700. if err != nil {
  701. sendErrorResponse(w, "Invalid src given")
  702. return
  703. }
  704. //Translate it to realpath
  705. realpath, _ := userinfo.VirtualPathToRealPath(targetTrashedFile)
  706. if !fileExists(realpath) {
  707. sendErrorResponse(w, "File not exists")
  708. return
  709. }
  710. //Check if this is really a trashed file
  711. if filepath.Base(filepath.Dir(realpath)) != ".trash" {
  712. sendErrorResponse(w, "File not in trashbin")
  713. return
  714. }
  715. //OK to proceed.
  716. targetPath := filepath.ToSlash(filepath.Dir(filepath.Dir(realpath))) + "/" + strings.TrimSuffix(filepath.Base(realpath), filepath.Ext(filepath.Base(realpath)))
  717. //log.Println(targetPath);
  718. os.Rename(realpath, targetPath)
  719. //Check if the parent dir has no more fileds. If yes, remove it
  720. filescounter, _ := filepath.Glob(filepath.Dir(realpath) + "/*")
  721. if len(filescounter) == 0 {
  722. os.Remove(filepath.Dir(realpath))
  723. }
  724. sendOK(w)
  725. }
  726. //Clear all trashed file in the system
  727. func system_fs_clearTrashBin(w http.ResponseWriter, r *http.Request) {
  728. u, err := userHandler.GetUserInfoFromRequest(w, r)
  729. if err != nil {
  730. sendErrorResponse(w, "User not logged in")
  731. return
  732. }
  733. username := u.Username
  734. fileList, err := system_fs_listTrash(username)
  735. if err != nil {
  736. sendErrorResponse(w, "Unable to clear trash: "+err.Error())
  737. return
  738. }
  739. //Get list success. Remove each of them.
  740. for _, file := range fileList {
  741. isOwner := u.IsOwnerOfFile(file)
  742. if isOwner {
  743. //This user own this system. Remove this file from his quota
  744. u.RemoveOwnershipFromFile(file)
  745. }
  746. os.RemoveAll(file)
  747. //Check if its parent directory have no files. If yes, remove the dir itself as well.
  748. filesInThisTrashBin, _ := filepath.Glob(filepath.Dir(file) + "/*")
  749. if len(filesInThisTrashBin) == 0 {
  750. os.Remove(filepath.Dir(file))
  751. }
  752. }
  753. sendOK(w)
  754. }
  755. //Get all trash in a string list
  756. func system_fs_listTrash(username string) ([]string, error) {
  757. userinfo, _ := userHandler.GetUserInfoFromUsername(username)
  758. scanningRoots := []string{}
  759. //Get all roots to scan
  760. for _, storage := range userinfo.GetAllFileSystemHandler() {
  761. storageRoot := storage.Path
  762. scanningRoots = append(scanningRoots, storageRoot)
  763. }
  764. files := []string{}
  765. for _, rootPath := range scanningRoots {
  766. err := filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error {
  767. oneLevelUpper := filepath.Base(filepath.Dir(path))
  768. if oneLevelUpper == ".trash" {
  769. //This is a trashbin dir.
  770. files = append(files, path)
  771. }
  772. return nil
  773. })
  774. if err != nil {
  775. return []string{}, errors.New("Failed to scan file system.")
  776. }
  777. }
  778. return files, nil
  779. }
  780. /*
  781. Handle new file or folder functions
  782. Required information
  783. @type {folder / file}
  784. @ext {any that is listed in the template folder}
  785. if no paramter is passed in, default listing all the supported template file
  786. */
  787. func system_fs_handleNewObjects(w http.ResponseWriter, r *http.Request) {
  788. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  789. if err != nil {
  790. sendErrorResponse(w, "User not logged in")
  791. return
  792. }
  793. fileType, _ := mv(r, "type", true) //File creation type, {file, folder}
  794. vsrc, _ := mv(r, "src", true) //Virtual file source folder, do not include filename
  795. filename, _ := mv(r, "filename", true) //Filename for the new file
  796. if fileType == "" && filename == "" {
  797. //List all the supported new filetype
  798. if !fileExists("system/newitem/") {
  799. os.MkdirAll("system/newitem/", 0755)
  800. }
  801. type newItemObject struct {
  802. Desc string
  803. Ext string
  804. }
  805. var newItemList []newItemObject
  806. newItemTemplate, _ := filepath.Glob("system/newitem/*")
  807. for _, file := range newItemTemplate {
  808. thisItem := new(newItemObject)
  809. thisItem.Desc = strings.TrimSuffix(filepath.Base(file), filepath.Ext(file))
  810. thisItem.Ext = filepath.Ext(file)[1:]
  811. newItemList = append(newItemList, *thisItem)
  812. }
  813. jsonString, err := json.Marshal(newItemList)
  814. if err != nil {
  815. log.Println("*File System* Unable to parse JSON string for new item list!")
  816. sendErrorResponse(w, "Unable to parse new item list. See server log for more information.")
  817. return
  818. }
  819. sendJSONResponse(w, string(jsonString))
  820. return
  821. } else if fileType != "" && filename != "" {
  822. if vsrc == "" {
  823. sendErrorResponse(w, "Missing paramter: 'src'")
  824. return
  825. }
  826. //Translate the path to realpath
  827. rpath, err := userinfo.VirtualPathToRealPath(vsrc)
  828. if err != nil {
  829. sendErrorResponse(w, "Invalid path given.")
  830. return
  831. }
  832. //Check if directory is readonly
  833. accmode := userinfo.GetPathAccessPermission(vsrc)
  834. if accmode == "readonly" {
  835. sendErrorResponse(w, "This directory is Read Only.")
  836. return
  837. } else if accmode == "denied" {
  838. sendErrorResponse(w, "Access Denied")
  839. return
  840. }
  841. //Check if the file already exists. If yes, fix its filename.
  842. newfilePath := rpath + filename
  843. if fileType == "file" {
  844. for fileExists(newfilePath) {
  845. sendErrorResponse(w, "Given filename already exists.")
  846. return
  847. }
  848. ext := filepath.Ext(filename)
  849. if ext == "" {
  850. //This is a file with no extension.
  851. f, err := os.Create(newfilePath)
  852. if err != nil {
  853. log.Println("*File System* " + err.Error())
  854. sendErrorResponse(w, err.Error())
  855. return
  856. }
  857. f.Close()
  858. } else {
  859. templateFile, _ := filepath.Glob("system/newitem/*" + ext)
  860. if len(templateFile) == 0 {
  861. //This file extension is not in template
  862. f, err := os.Create(newfilePath)
  863. if err != nil {
  864. log.Println("*File System* " + err.Error())
  865. sendErrorResponse(w, err.Error())
  866. return
  867. }
  868. f.Close()
  869. } else {
  870. //Copy file from templateFile[0] to current dir with the given name
  871. input, _ := ioutil.ReadFile(templateFile[0])
  872. err := ioutil.WriteFile(newfilePath, input, 0755)
  873. if err != nil {
  874. log.Println("*File System* " + err.Error())
  875. sendErrorResponse(w, err.Error())
  876. return
  877. }
  878. }
  879. }
  880. } else if fileType == "folder" {
  881. if fileExists(newfilePath) {
  882. sendErrorResponse(w, "Given folder already exists.")
  883. return
  884. }
  885. //Create the folder at target location
  886. err := os.Mkdir(newfilePath, 0755)
  887. if err != nil {
  888. sendErrorResponse(w, err.Error())
  889. return
  890. }
  891. }
  892. sendJSONResponse(w, "\"OK\"")
  893. } else {
  894. sendErrorResponse(w, "Missing paramter(s).")
  895. return
  896. }
  897. }
  898. /*
  899. Handle file operations via WebSocket
  900. This handler only handle zip, unzip, copy and move. Not other operations.
  901. For other operations, please use the legacy handleOpr endpoint
  902. */
  903. func system_fs_handleWebSocketOpr(w http.ResponseWriter, r *http.Request) {
  904. //Get and check user permission
  905. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  906. if err != nil {
  907. sendErrorResponse(w, "User not logged in")
  908. return
  909. }
  910. operation, _ := mv(r, "opr", false) //Accept copy and move
  911. vsrcFiles, _ := mv(r, "src", false)
  912. vdestFile, _ := mv(r, "dest", false)
  913. existsOpr, _ := mv(r, "existsresp", false)
  914. if existsOpr == "" {
  915. existsOpr = "keep"
  916. }
  917. //Decode the source file list
  918. var sourceFiles []string
  919. tmp := []string{}
  920. decodedSourceFiles, _ := url.QueryUnescape(vsrcFiles)
  921. err = json.Unmarshal([]byte(decodedSourceFiles), &sourceFiles)
  922. if err != nil {
  923. log.Println("Source file JSON parse error.", err.Error())
  924. sendErrorResponse(w, "Source file JSON parse error.")
  925. return
  926. }
  927. //Bugged char filtering
  928. for _, src := range sourceFiles {
  929. tmp = append(tmp, strings.ReplaceAll(src, "{{plug_sign}}", "+"))
  930. }
  931. sourceFiles = tmp
  932. vdestFile = strings.ReplaceAll(vdestFile, "{{plug_sign}}", "+")
  933. //Decode the target position
  934. escapedVdest, _ := url.QueryUnescape(vdestFile)
  935. vdestFile = escapedVdest
  936. rdestFile, _ := userinfo.VirtualPathToRealPath(vdestFile)
  937. //Permission checking
  938. if !userinfo.CanWrite(vdestFile) {
  939. log.Println(vdestFile)
  940. w.WriteHeader(http.StatusForbidden)
  941. w.Write([]byte("403 - Access Denied"))
  942. return
  943. }
  944. //Check if opr is suported
  945. if operation == "move" || operation == "copy" || operation == "zip" || operation == "unzip" {
  946. } else {
  947. log.Println("This file operation is not supported on WebSocket file operations endpoint. Please use the legacy endpoint instead. Received: ", operation)
  948. w.WriteHeader(http.StatusInternalServerError)
  949. w.Write([]byte("500 - Not supported operation"))
  950. return
  951. }
  952. //Upgrade to websocket
  953. var upgrader = websocket.Upgrader{}
  954. c, err := upgrader.Upgrade(w, r, nil)
  955. if err != nil {
  956. w.WriteHeader(http.StatusInternalServerError)
  957. w.Write([]byte("500 - " + err.Error()))
  958. log.Print("Websocket Upgrade Error:", err.Error())
  959. return
  960. }
  961. type ProgressUpdate struct {
  962. LatestFile string
  963. Progress int
  964. Error string
  965. }
  966. if operation == "zip" {
  967. //Zip files
  968. outputFilename := filepath.Join(rdestFile, filepath.Base(rdestFile)) + ".zip"
  969. if len(sourceFiles) == 1 {
  970. //Use the basename of the source file as zip file name
  971. outputFilename = filepath.Join(rdestFile, filepath.Base(sourceFiles[0])) + ".zip"
  972. }
  973. //Translate source Files into real paths
  974. realSourceFiles := []string{}
  975. for _, vsrcs := range sourceFiles {
  976. rsrc, err := userinfo.VirtualPathToRealPath(vsrcs)
  977. if err != nil {
  978. stopStatus := ProgressUpdate{
  979. LatestFile: filepath.Base(rsrc),
  980. Progress: -1,
  981. Error: "File not exists",
  982. }
  983. js, _ := json.Marshal(stopStatus)
  984. c.WriteMessage(1, js)
  985. c.Close()
  986. }
  987. realSourceFiles = append(realSourceFiles, rsrc)
  988. }
  989. //Create the zip file
  990. fs.ArozZipFileWithProgress(realSourceFiles, outputFilename, false, func(currentFilename string, _ int, _ int, progress float64) {
  991. currentStatus := ProgressUpdate{
  992. LatestFile: currentFilename,
  993. Progress: int(math.Ceil(progress)),
  994. Error: "",
  995. }
  996. js, _ := json.Marshal(currentStatus)
  997. c.WriteMessage(1, js)
  998. })
  999. } else if operation == "unzip" {
  1000. //Check if the target destination exists and writable
  1001. if !userinfo.CanWrite(vdestFile) {
  1002. stopStatus := ProgressUpdate{
  1003. LatestFile: filepath.Base(vdestFile),
  1004. Progress: -1,
  1005. Error: "Access Denied: No Write Permission",
  1006. }
  1007. js, _ := json.Marshal(stopStatus)
  1008. c.WriteMessage(1, js)
  1009. c.Close()
  1010. }
  1011. //Create the destination folder
  1012. os.MkdirAll(rdestFile, 0755)
  1013. //Convert the src files into realpaths
  1014. realSourceFiles := []string{}
  1015. for _, vsrcs := range sourceFiles {
  1016. rsrc, err := userinfo.VirtualPathToRealPath(vsrcs)
  1017. if err != nil {
  1018. stopStatus := ProgressUpdate{
  1019. LatestFile: filepath.Base(rsrc),
  1020. Progress: -1,
  1021. Error: "File not exists",
  1022. }
  1023. js, _ := json.Marshal(stopStatus)
  1024. c.WriteMessage(1, js)
  1025. c.Close()
  1026. }
  1027. realSourceFiles = append(realSourceFiles, rsrc)
  1028. }
  1029. //Unzip the files
  1030. fs.ArozUnzipFileWithProgress(realSourceFiles, rdestFile, func(currentFile string, filecount int, totalfile int, progress float64) {
  1031. //Generate the status update struct
  1032. currentStatus := ProgressUpdate{
  1033. LatestFile: filepath.Base(currentFile),
  1034. Progress: int(math.Ceil(progress)),
  1035. Error: "",
  1036. }
  1037. js, _ := json.Marshal(currentStatus)
  1038. c.WriteMessage(1, js)
  1039. })
  1040. } else {
  1041. //Other operations that allow multiple source files to handle one by one
  1042. for i := 0; i < len(sourceFiles); i++ {
  1043. vsrcFile := sourceFiles[i]
  1044. rsrcFile, _ := userinfo.VirtualPathToRealPath(vsrcFile)
  1045. //c.WriteMessage(1, message)
  1046. if !fileExists(rsrcFile) {
  1047. //This source file not exists. Report Error and Stop
  1048. stopStatus := ProgressUpdate{
  1049. LatestFile: filepath.Base(rsrcFile),
  1050. Progress: -1,
  1051. Error: "File not exists",
  1052. }
  1053. js, _ := json.Marshal(stopStatus)
  1054. c.WriteMessage(1, js)
  1055. c.Close()
  1056. return
  1057. }
  1058. if operation == "move" {
  1059. err := fs.FileMove(rsrcFile, rdestFile, existsOpr, false, func(progress int, currentFile string) {
  1060. //Multply child progress to parent progress
  1061. blockRatio := float64(100) / float64(len(sourceFiles))
  1062. overallRatio := blockRatio*float64(i) + blockRatio*(float64(progress)/float64(100))
  1063. //Construct return struct
  1064. currentStatus := ProgressUpdate{
  1065. LatestFile: filepath.Base(currentFile),
  1066. Progress: int(overallRatio),
  1067. Error: "",
  1068. }
  1069. js, _ := json.Marshal(currentStatus)
  1070. c.WriteMessage(1, js)
  1071. })
  1072. //Handle move starting error
  1073. if err != nil {
  1074. stopStatus := ProgressUpdate{
  1075. LatestFile: filepath.Base(rsrcFile),
  1076. Progress: -1,
  1077. Error: err.Error(),
  1078. }
  1079. js, _ := json.Marshal(stopStatus)
  1080. c.WriteMessage(1, js)
  1081. c.Close()
  1082. return
  1083. }
  1084. } else if operation == "copy" {
  1085. err := fs.FileCopy(rsrcFile, rdestFile, existsOpr, func(progress int, currentFile string) {
  1086. //Multply child progress to parent progress
  1087. blockRatio := float64(100) / float64(len(sourceFiles))
  1088. overallRatio := blockRatio*float64(i) + blockRatio*(float64(progress)/float64(100))
  1089. //Construct return struct
  1090. currentStatus := ProgressUpdate{
  1091. LatestFile: filepath.Base(currentFile),
  1092. Progress: int(overallRatio),
  1093. Error: "",
  1094. }
  1095. js, _ := json.Marshal(currentStatus)
  1096. c.WriteMessage(1, js)
  1097. })
  1098. //Handle Copy starting error
  1099. if err != nil {
  1100. stopStatus := ProgressUpdate{
  1101. LatestFile: filepath.Base(rsrcFile),
  1102. Progress: -1,
  1103. Error: err.Error(),
  1104. }
  1105. js, _ := json.Marshal(stopStatus)
  1106. c.WriteMessage(1, js)
  1107. c.Close()
  1108. return
  1109. }
  1110. }
  1111. }
  1112. }
  1113. //Close WebSocket connection after finished
  1114. time.Sleep(1 * time.Second)
  1115. c.WriteControl(8, []byte{}, time.Now().Add(time.Second))
  1116. c.Close()
  1117. }
  1118. /*
  1119. Handle file operations
  1120. Support {move, copy, delete, recycle, rename}
  1121. */
  1122. //Handle file operations.
  1123. func system_fs_handleOpr(w http.ResponseWriter, r *http.Request) {
  1124. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  1125. if err != nil {
  1126. sendErrorResponse(w, "User not logged in")
  1127. return
  1128. }
  1129. operation, _ := mv(r, "opr", true)
  1130. vsrcFiles, _ := mv(r, "src", true)
  1131. vdestFile, _ := mv(r, "dest", true)
  1132. vnfilenames, _ := mv(r, "new", true) //Only use when rename or create new file / folder
  1133. //Check if operation valid.
  1134. if operation == "" {
  1135. //Undefined operations.
  1136. sendErrorResponse(w, "Undefined operations paramter: Missing 'opr' in request header.")
  1137. return
  1138. }
  1139. //As the user can pass in multiple source files at the same time, parse sourceFiles from json string
  1140. var sourceFiles []string
  1141. //This line is required in order to allow passing of special charaters
  1142. decodedSourceFiles := system_fs_specialURIDecode(vsrcFiles)
  1143. err = json.Unmarshal([]byte(decodedSourceFiles), &sourceFiles)
  1144. if err != nil {
  1145. sendErrorResponse(w, "Source file JSON parse error.")
  1146. return
  1147. }
  1148. //Check if new filenames are also valid. If yes, translate it into string array
  1149. var newFilenames []string
  1150. if vnfilenames != "" {
  1151. vnfilenames, _ := url.QueryUnescape(vnfilenames)
  1152. err = json.Unmarshal([]byte(vnfilenames), &newFilenames)
  1153. if err != nil {
  1154. sendErrorResponse(w, "Unable to parse JSON for new filenames")
  1155. return
  1156. }
  1157. }
  1158. if operation == "zip" {
  1159. //Zip operation. Parse the real filepath list
  1160. rsrcFiles := []string{}
  1161. rdestFile, _ := userinfo.VirtualPathToRealPath(vdestFile)
  1162. for _, vsrcFile := range sourceFiles {
  1163. rsrcFile, _ := userinfo.VirtualPathToRealPath(string(vsrcFile))
  1164. if fileExists(rsrcFile) {
  1165. rsrcFiles = append(rsrcFiles, rsrcFile)
  1166. }
  1167. }
  1168. zipFilename := rdestFile
  1169. if fs.IsDir(rdestFile) {
  1170. //Append the filename to it
  1171. if len(rsrcFiles) == 1 {
  1172. zipFilename = filepath.Join(rdestFile, strings.TrimSuffix(filepath.Base(rsrcFiles[0]), filepath.Ext(filepath.Base(rsrcFiles[0])))+".zip")
  1173. } else if len(rsrcFiles) > 1 {
  1174. zipFilename = filepath.Join(rdestFile, filepath.Base(filepath.Dir(rsrcFiles[0]))+".zip")
  1175. }
  1176. }
  1177. //Create a zip file at target location
  1178. err := fs.ArozZipFile(rsrcFiles, zipFilename, false)
  1179. if err != nil {
  1180. sendErrorResponse(w, err.Error())
  1181. return
  1182. }
  1183. } else {
  1184. //For operations that is handled file by file
  1185. for i, vsrcFile := range sourceFiles {
  1186. //Convert the virtual path to realpath on disk
  1187. rsrcFile, _ := userinfo.VirtualPathToRealPath(string(vsrcFile))
  1188. rdestFile, _ := userinfo.VirtualPathToRealPath(vdestFile)
  1189. //Check if the source file exists
  1190. if !fileExists(rsrcFile) {
  1191. /*
  1192. Special edge case handler:
  1193. There might be edge case that files are stored in URIEncoded methods
  1194. e.g. abc def.mp3 --> abc%20cdf.mp3
  1195. In this case, this logic statement should be able to handle this
  1196. */
  1197. edgeCaseFilename := filepath.Join(filepath.Dir(rsrcFile), system_fs_specialURIEncode(filepath.Base(rsrcFile)))
  1198. if fileExists(edgeCaseFilename) {
  1199. rsrcFile = edgeCaseFilename
  1200. } else {
  1201. sendErrorResponse(w, "Source file not exists.")
  1202. return
  1203. }
  1204. }
  1205. if operation == "rename" {
  1206. //Check if the usage is correct.
  1207. if vdestFile != "" {
  1208. sendErrorResponse(w, "Rename only accept 'src' and 'new'. Please use move if you want to move a file.")
  1209. return
  1210. }
  1211. //Check if new name paramter is passed in.
  1212. if len(newFilenames) == 0 {
  1213. sendErrorResponse(w, "Missing paramter (JSON string): 'new'")
  1214. return
  1215. }
  1216. //Check if the source filenames and new filenanmes match
  1217. if len(newFilenames) != len(sourceFiles) {
  1218. sendErrorResponse(w, "New filenames do not match with source filename's length.")
  1219. return
  1220. }
  1221. //Check if the target dir is not readonly
  1222. accmode := userinfo.GetPathAccessPermission(string(vsrcFile))
  1223. if accmode == "readonly" {
  1224. sendErrorResponse(w, "This directory is Read Only.")
  1225. return
  1226. } else if accmode == "denied" {
  1227. sendErrorResponse(w, "Access Denied")
  1228. return
  1229. }
  1230. thisFilename := newFilenames[i]
  1231. //Check if the name already exists. If yes, return false
  1232. if fileExists(filepath.Dir(rsrcFile) + "/" + thisFilename) {
  1233. sendErrorResponse(w, "File already exists")
  1234. return
  1235. }
  1236. //Everything is ok. Rename the file.
  1237. targetNewName := filepath.Dir(rsrcFile) + "/" + thisFilename
  1238. err = os.Rename(rsrcFile, targetNewName)
  1239. if err != nil {
  1240. sendErrorResponse(w, err.Error())
  1241. return
  1242. }
  1243. } else if operation == "move" {
  1244. //File move operation. Check if the source file / dir and target directory exists
  1245. /*
  1246. Example usage from file explorer
  1247. $.ajax({
  1248. type: 'POST',
  1249. url: `/system/file_system/fileOpr`,
  1250. data: {opr: "move" ,src: JSON.stringify(fileList), dest: targetDir},
  1251. success: function(data){
  1252. if (data.error !== undefined){
  1253. msgbox("remove",data.error);
  1254. }else{
  1255. //OK, do something
  1256. }
  1257. }
  1258. });
  1259. */
  1260. if !fileExists(rsrcFile) {
  1261. sendErrorResponse(w, "Source file not exists")
  1262. return
  1263. }
  1264. //Check if the source file is read only.
  1265. accmode := userinfo.GetPathAccessPermission(string(vsrcFile))
  1266. if accmode == "readonly" {
  1267. sendErrorResponse(w, "This source file is Read Only.")
  1268. return
  1269. } else if accmode == "denied" {
  1270. sendErrorResponse(w, "Access Denied")
  1271. return
  1272. }
  1273. if rdestFile == "" {
  1274. sendErrorResponse(w, "Undefined dest location.")
  1275. return
  1276. }
  1277. //Get exists overwrite mode
  1278. existsOpr, _ := mv(r, "existsresp", true)
  1279. //Check if use fast move instead
  1280. //Check if the source and destination folder are under the same root. If yes, use os.Rename for faster move operations
  1281. underSameRoot := false
  1282. //Check if the two files are under the same user root path
  1283. srcAbs, _ := filepath.Abs(rsrcFile)
  1284. destAbs, _ := filepath.Abs(rdestFile)
  1285. //Check other storage path and see if they are under the same root
  1286. for _, rootPath := range userinfo.GetAllFileSystemHandler() {
  1287. thisRoot := rootPath.Path
  1288. thisRootAbs, err := filepath.Abs(thisRoot)
  1289. if err != nil {
  1290. continue
  1291. }
  1292. if strings.Contains(srcAbs, thisRootAbs) && strings.Contains(destAbs, thisRootAbs) {
  1293. underSameRoot = true
  1294. }
  1295. }
  1296. //Updates 19-10-2020: Added ownership management to file move and copy
  1297. userinfo.RemoveOwnershipFromFile(rsrcFile)
  1298. err = fs.FileMove(rsrcFile, rdestFile, existsOpr, underSameRoot, nil)
  1299. if err != nil {
  1300. sendErrorResponse(w, err.Error())
  1301. //Restore the ownership if remove failed
  1302. userinfo.SetOwnerOfFile(rsrcFile)
  1303. return
  1304. }
  1305. //Set user to own the new file
  1306. userinfo.SetOwnerOfFile(filepath.ToSlash(filepath.Clean(rdestFile)) + "/" + filepath.Base(rsrcFile))
  1307. } else if operation == "copy" {
  1308. //Copy file. See move example and change 'opr' to 'copy'
  1309. if !fileExists(rsrcFile) {
  1310. sendErrorResponse(w, "Source file not exists")
  1311. return
  1312. }
  1313. //Check if the desintation is read only.
  1314. if !userinfo.CanWrite(vdestFile) {
  1315. sendErrorResponse(w, "Access Denied.")
  1316. return
  1317. }
  1318. if !fileExists(rdestFile) {
  1319. if fileExists(filepath.Dir(rdestFile)) {
  1320. //User pass in the whole path for the folder. Report error usecase.
  1321. sendErrorResponse(w, "Dest location should be an existing folder instead of the full path of the copied file.")
  1322. return
  1323. }
  1324. sendErrorResponse(w, "Dest folder not found")
  1325. return
  1326. }
  1327. existsOpr, _ := mv(r, "existsresp", true)
  1328. //Check if the user have space for the extra file
  1329. if !userinfo.StorageQuota.HaveSpace(fs.GetFileSize(rdestFile)) {
  1330. sendErrorResponse(w, "Storage Quota Full")
  1331. return
  1332. }
  1333. err = fs.FileCopy(rsrcFile, rdestFile, existsOpr, nil)
  1334. if err != nil {
  1335. sendErrorResponse(w, err.Error())
  1336. return
  1337. }
  1338. //Set user to own this file
  1339. userinfo.SetOwnerOfFile(filepath.ToSlash(filepath.Clean(rdestFile)) + "/" + filepath.Base(rsrcFile))
  1340. } else if operation == "delete" {
  1341. //Delete the file permanently
  1342. if !fileExists(rsrcFile) {
  1343. //Check if it is a non escapted file instead
  1344. sendErrorResponse(w, "Source file not exists")
  1345. return
  1346. }
  1347. //Check if the desintation is read only.
  1348. /*
  1349. accmode := userinfo.GetPathAccessPermission(string(vsrcFile))
  1350. if accmode == "readonly" {
  1351. sendErrorResponse(w, "This directory is Read Only.")
  1352. return
  1353. } else if accmode == "denied" {
  1354. sendErrorResponse(w, "Access Denied")
  1355. return
  1356. }
  1357. */
  1358. if !userinfo.CanWrite(vsrcFile) {
  1359. sendErrorResponse(w, "Access Denied.")
  1360. return
  1361. }
  1362. //Check if the user own this file
  1363. isOwner := userinfo.IsOwnerOfFile(rsrcFile)
  1364. if isOwner {
  1365. //This user own this system. Remove this file from his quota
  1366. userinfo.RemoveOwnershipFromFile(rsrcFile)
  1367. }
  1368. //Check if this file has any cached files. If yes, remove it
  1369. if fileExists(filepath.ToSlash(filepath.Dir(rsrcFile)) + "/.cache/" + filepath.Base(rsrcFile) + ".jpg") {
  1370. os.Remove(filepath.ToSlash(filepath.Dir(rsrcFile)) + "/.cache/" + filepath.Base(rsrcFile) + ".jpg")
  1371. }
  1372. //Clear the cache folder if there is no files inside
  1373. fc, _ := filepath.Glob(filepath.ToSlash(filepath.Dir(rsrcFile)) + "/.cache/*")
  1374. if len(fc) == 0 {
  1375. os.Remove(filepath.ToSlash(filepath.Dir(rsrcFile)) + "/.cache/")
  1376. }
  1377. os.RemoveAll(rsrcFile)
  1378. } else if operation == "recycle" {
  1379. //Put it into a subfolder named trash and allow it to to be removed later
  1380. if !fileExists(rsrcFile) {
  1381. //Check if it is a non escapted file instead
  1382. sendErrorResponse(w, "Source file not exists")
  1383. return
  1384. }
  1385. //Check if the upload target is read only.
  1386. //Updates 20 Jan 2021: Replace with CanWrite handler
  1387. /*
  1388. accmode := userinfo.GetPathAccessPermission(string(vsrcFile))
  1389. if accmode == "readonly" {
  1390. sendErrorResponse(w, "This directory is Read Only.")
  1391. return
  1392. } else if accmode == "denied" {
  1393. sendErrorResponse(w, "Access Denied")
  1394. return
  1395. }*/
  1396. if !userinfo.CanWrite(vsrcFile) {
  1397. sendErrorResponse(w, "Access Denied.")
  1398. return
  1399. }
  1400. //Check if this file has any cached files. If yes, remove it
  1401. if fileExists(filepath.ToSlash(filepath.Dir(rsrcFile)) + "/.cache/" + filepath.Base(rsrcFile) + ".jpg") {
  1402. os.Remove(filepath.ToSlash(filepath.Dir(rsrcFile)) + "/.cache/" + filepath.Base(rsrcFile) + ".jpg")
  1403. }
  1404. //Clear the cache folder if there is no files inside
  1405. fc, _ := filepath.Glob(filepath.ToSlash(filepath.Dir(rsrcFile)) + "/.cache/*")
  1406. if len(fc) == 0 {
  1407. os.Remove(filepath.ToSlash(filepath.Dir(rsrcFile)) + "/.cache/")
  1408. }
  1409. //Create a trash directory for this folder
  1410. trashDir := filepath.ToSlash(filepath.Dir(rsrcFile)) + "/.trash/"
  1411. os.MkdirAll(trashDir, 0755)
  1412. hidden.HideFile(trashDir)
  1413. os.Rename(rsrcFile, trashDir+filepath.Base(rsrcFile)+"."+Int64ToString(GetUnixTime()))
  1414. } else if operation == "unzip" {
  1415. //Unzip the file to destination
  1416. //Check if the user can write to the target dest file
  1417. if userinfo.CanWrite(string(vdestFile)) == false {
  1418. sendErrorResponse(w, "Access Denied.")
  1419. return
  1420. }
  1421. //Make the rdest directory if not exists
  1422. if !fileExists(rdestFile) {
  1423. err = os.MkdirAll(rdestFile, 0755)
  1424. if err != nil {
  1425. sendErrorResponse(w, err.Error())
  1426. return
  1427. }
  1428. }
  1429. //OK! Unzip to destination
  1430. err := fs.Unzip(rsrcFile, rdestFile)
  1431. if err != nil {
  1432. sendErrorResponse(w, err.Error())
  1433. return
  1434. }
  1435. } else {
  1436. sendErrorResponse(w, "Unknown file opeartion given.")
  1437. return
  1438. }
  1439. }
  1440. }
  1441. sendJSONResponse(w, "\"OK\"")
  1442. return
  1443. }
  1444. //Allow systems to store key value pairs in the database as preferences.
  1445. func system_fs_handleUserPreference(w http.ResponseWriter, r *http.Request) {
  1446. username, err := authAgent.GetUserName(w, r)
  1447. if err != nil {
  1448. sendErrorResponse(w, "User not logged in")
  1449. return
  1450. }
  1451. key, _ := mv(r, "key", false)
  1452. value, _ := mv(r, "value", false)
  1453. remove, _ := mv(r, "remove", false)
  1454. if key != "" && value == "" && remove == "" {
  1455. //Get mode. Read the prefernece with given key
  1456. result := ""
  1457. err := sysdb.Read("fs", "pref/"+key+"/"+username, &result)
  1458. if err != nil {
  1459. sendJSONResponse(w, "{\"error\":\"Key not found.\"}")
  1460. return
  1461. }
  1462. sendTextResponse(w, result)
  1463. } else if key != "" && value == "" && remove == "true" {
  1464. //Remove mode. Delete this key from sysdb
  1465. err := sysdb.Delete("fs", "pref/"+key+"/"+username)
  1466. if err != nil {
  1467. sendErrorResponse(w, err.Error())
  1468. }
  1469. sendOK(w)
  1470. } else if key != "" && value != "" {
  1471. //Set mode. Set the preference with given key
  1472. if len(value) > 1024 {
  1473. //Size too big. Reject storage
  1474. sendErrorResponse(w, "Preference value too long. Preference value can only store maximum 1024 characters.")
  1475. return
  1476. }
  1477. sysdb.Write("fs", "pref/"+key+"/"+username, value)
  1478. sendOK(w)
  1479. }
  1480. }
  1481. func system_fs_removeUserPreferences(username string) {
  1482. entries, err := sysdb.ListTable("fs")
  1483. if err != nil {
  1484. return
  1485. }
  1486. for _, keypairs := range entries {
  1487. if strings.Contains(string(keypairs[0]), "pref/") && strings.Contains(string(keypairs[0]), "/"+username) {
  1488. //Remove this preference
  1489. sysdb.Delete("fs", string(keypairs[0]))
  1490. }
  1491. }
  1492. }
  1493. func system_fs_listDrives(w http.ResponseWriter, r *http.Request) {
  1494. if authAgent.CheckAuth(r) == false {
  1495. sendErrorResponse(w, "User not logged in")
  1496. return
  1497. }
  1498. userinfo, _ := userHandler.GetUserInfoFromRequest(w, r)
  1499. type driveInfo struct {
  1500. Drivepath string
  1501. DriveFreeSpace uint64
  1502. DriveTotalSpace uint64
  1503. DriveAvailSpace uint64
  1504. }
  1505. var drives []driveInfo
  1506. if runtime.GOOS == "windows" {
  1507. //Under windows
  1508. for _, drive := range "ABCDEFGHIJKLMNOPQRSTUVWXYZ" {
  1509. f, err := os.Open(string(drive) + ":\\")
  1510. if err == nil {
  1511. thisdrive := new(driveInfo)
  1512. thisdrive.Drivepath = string(drive) + ":\\"
  1513. free, total, avail := storage.GetDriveCapacity(string(drive) + ":\\")
  1514. thisdrive.DriveFreeSpace = free
  1515. thisdrive.DriveTotalSpace = total
  1516. thisdrive.DriveAvailSpace = avail
  1517. drives = append(drives, *thisdrive)
  1518. f.Close()
  1519. }
  1520. }
  1521. } else {
  1522. //Under linux environment
  1523. //Append all the virtual directories root as root instead
  1524. storageDevices := []string{}
  1525. for _, fshandler := range userinfo.GetAllFileSystemHandler() {
  1526. storageDevices = append(storageDevices, fshandler.Path)
  1527. }
  1528. //List all storage information of each devices
  1529. for _, dev := range storageDevices {
  1530. thisdrive := new(driveInfo)
  1531. thisdrive.Drivepath = filepath.Base(dev)
  1532. free, total, avail := storage.GetDriveCapacity(string(dev))
  1533. thisdrive.DriveFreeSpace = free
  1534. thisdrive.DriveTotalSpace = total
  1535. thisdrive.DriveAvailSpace = avail
  1536. drives = append(drives, *thisdrive)
  1537. }
  1538. }
  1539. jsonString, _ := json.Marshal(drives)
  1540. sendJSONResponse(w, string(jsonString))
  1541. }
  1542. func system_fs_listRoot(w http.ResponseWriter, r *http.Request) {
  1543. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  1544. if err != nil {
  1545. sendErrorResponse(w, err.Error())
  1546. return
  1547. }
  1548. username := userinfo.Username
  1549. userRoot, _ := mv(r, "user", false)
  1550. if userRoot == "true" {
  1551. type fileObject struct {
  1552. Filename string
  1553. Filepath string
  1554. IsDir bool
  1555. }
  1556. //List the root media folders under user:/
  1557. filesInUserRoot := []fileObject{}
  1558. filesInRoot, _ := filepath.Glob(filepath.ToSlash(filepath.Clean(*root_directory)) + "/users/" + username + "/*")
  1559. for _, file := range filesInRoot {
  1560. thisFile := new(fileObject)
  1561. thisFile.Filename = filepath.Base(file)
  1562. thisFile.Filepath, _ = userinfo.RealPathToVirtualPath(file)
  1563. thisFile.IsDir = IsDir(file)
  1564. filesInUserRoot = append(filesInUserRoot, *thisFile)
  1565. }
  1566. jsonString, _ := json.Marshal(filesInUserRoot)
  1567. sendJSONResponse(w, string(jsonString))
  1568. } else {
  1569. type rootObject struct {
  1570. RootName string
  1571. RootPath string
  1572. }
  1573. var roots []rootObject
  1574. for _, store := range userinfo.GetAllFileSystemHandler() {
  1575. var thisDevice = new(rootObject)
  1576. thisDevice.RootName = store.Name
  1577. thisDevice.RootPath = store.UUID + ":/"
  1578. roots = append(roots, *thisDevice)
  1579. }
  1580. jsonString, _ := json.Marshal(roots)
  1581. sendJSONResponse(w, string(jsonString))
  1582. }
  1583. }
  1584. /*
  1585. Special Glob for handling path with [ or ] inside.
  1586. You can also pass in normal path for globing if you are not sure.
  1587. */
  1588. func system_fs_specialGlob(path string) ([]string, error) {
  1589. files, err := filepath.Glob(path)
  1590. if err != nil {
  1591. return []string{}, err
  1592. }
  1593. if strings.Contains(path, "[") == true || strings.Contains(path, "]") == true {
  1594. if len(files) == 0 {
  1595. //Handle reverse check. Replace all [ and ] with *
  1596. newSearchPath := strings.ReplaceAll(path, "[", "?")
  1597. newSearchPath = strings.ReplaceAll(newSearchPath, "]", "?")
  1598. //Scan with all the similar structure except [ and ]
  1599. tmpFilelist, _ := filepath.Glob(newSearchPath)
  1600. for _, file := range tmpFilelist {
  1601. file = filepath.ToSlash(file)
  1602. if strings.Contains(file, filepath.ToSlash(filepath.Dir(path))) {
  1603. files = append(files, file)
  1604. }
  1605. }
  1606. }
  1607. }
  1608. //Convert all filepaths to slash
  1609. for i := 0; i < len(files); i++ {
  1610. files[i] = filepath.ToSlash(files[i])
  1611. }
  1612. return files, nil
  1613. }
  1614. func system_fs_specialURIDecode(inputPath string) string {
  1615. inputPath = strings.ReplaceAll(inputPath, "+", "{{plus_sign}}")
  1616. inputPath, _ = url.QueryUnescape(inputPath)
  1617. inputPath = strings.ReplaceAll(inputPath, "{{plus_sign}}", "+")
  1618. return inputPath
  1619. }
  1620. func system_fs_specialURIEncode(inputPath string) string {
  1621. inputPath = strings.ReplaceAll(inputPath, " ", "{{space_sign}}")
  1622. inputPath, _ = url.QueryUnescape(inputPath)
  1623. inputPath = strings.ReplaceAll(inputPath, "{{space_sign}}", "%20")
  1624. return inputPath
  1625. }
  1626. func system_fs_matchFileExt(inputFilename string, extArray []string) bool {
  1627. inputExt := filepath.Ext(inputFilename)
  1628. if stringInSlice(inputExt, extArray) {
  1629. return true
  1630. }
  1631. return false
  1632. }
  1633. //Handle file properties request
  1634. func system_fs_getFileProperties(w http.ResponseWriter, r *http.Request) {
  1635. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  1636. if err != nil {
  1637. sendErrorResponse(w, err.Error())
  1638. return
  1639. }
  1640. vpath, err := mv(r, "path", true)
  1641. if err != nil {
  1642. sendErrorResponse(w, "path not defined")
  1643. return
  1644. }
  1645. rpath, err := userinfo.VirtualPathToRealPath(vpath)
  1646. if err != nil {
  1647. sendErrorResponse(w, err.Error())
  1648. return
  1649. }
  1650. fileStat, err := os.Stat(rpath)
  1651. if err != nil {
  1652. sendErrorResponse(w, err.Error())
  1653. return
  1654. }
  1655. type fileProperties struct {
  1656. VirtualPath string
  1657. StoragePath string
  1658. Basename string
  1659. VirtualDirname string
  1660. StorageDirname string
  1661. Ext string
  1662. MimeType string
  1663. Filesize int64
  1664. Permission string
  1665. LastModTime string
  1666. LastModUnix int64
  1667. IsDirectory bool
  1668. Owner string
  1669. }
  1670. mime := "text/directory"
  1671. if !fileStat.IsDir() {
  1672. m, _, err := fs.GetMime(rpath)
  1673. if err != nil {
  1674. mime = ""
  1675. }
  1676. mime = m
  1677. }
  1678. filesize := fileStat.Size()
  1679. //Get file overall size if this is folder
  1680. if fileStat.IsDir() {
  1681. var size int64
  1682. filepath.Walk(rpath, func(_ string, info os.FileInfo, err error) error {
  1683. if err != nil {
  1684. return err
  1685. }
  1686. if !info.IsDir() {
  1687. size += info.Size()
  1688. }
  1689. return err
  1690. })
  1691. filesize = size
  1692. }
  1693. //Get file owner
  1694. owner := userinfo.GetFileOwner(rpath)
  1695. if owner == "" {
  1696. owner = "Unknown"
  1697. }
  1698. result := fileProperties{
  1699. VirtualPath: vpath,
  1700. StoragePath: filepath.Clean(rpath),
  1701. Basename: filepath.Base(rpath),
  1702. VirtualDirname: filepath.ToSlash(filepath.Dir(vpath)),
  1703. StorageDirname: filepath.ToSlash(filepath.Dir(rpath)),
  1704. Ext: filepath.Ext(rpath),
  1705. MimeType: mime,
  1706. Filesize: filesize,
  1707. Permission: fileStat.Mode().Perm().String(),
  1708. LastModTime: timeToString(fileStat.ModTime()),
  1709. LastModUnix: fileStat.ModTime().Unix(),
  1710. IsDirectory: fileStat.IsDir(),
  1711. Owner: owner,
  1712. }
  1713. jsonString, _ := json.Marshal(result)
  1714. sendJSONResponse(w, string(jsonString))
  1715. }
  1716. /*
  1717. List directory in the given path
  1718. Usage: Pass in dir like the following examples:
  1719. AOR:/Desktop <= Open /user/{username}/Desktop
  1720. S1:/ <= Open {uuid=S1}/
  1721. */
  1722. func system_fs_handleList(w http.ResponseWriter, r *http.Request) {
  1723. currentDir, _ := mv(r, "dir", true)
  1724. //Commented this line to handle dirname that contains "+" sign
  1725. //currentDir, _ = url.QueryUnescape(currentDir)
  1726. sortMode, _ := mv(r, "sort", true)
  1727. showHidden, _ := mv(r, "showHidden", true)
  1728. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  1729. if err != nil {
  1730. //user not logged in. Redirect to login page.
  1731. sendErrorResponse(w, "User not logged in")
  1732. return
  1733. }
  1734. if currentDir == "" {
  1735. sendErrorResponse(w, "Invalid dir given.")
  1736. return
  1737. }
  1738. //Pad a slash at the end of currentDir if not exists
  1739. if currentDir[len(currentDir)-1:] != "/" {
  1740. currentDir = currentDir + "/"
  1741. }
  1742. //Convert the virutal path to realpath
  1743. realpath, err := userinfo.VirtualPathToRealPath(currentDir)
  1744. if err != nil {
  1745. sendErrorResponse(w, "Error. Unable to parse path. "+err.Error())
  1746. return
  1747. }
  1748. if !fileExists(realpath) {
  1749. userRoot, _ := userinfo.VirtualPathToRealPath("user:/")
  1750. if filepath.Clean(realpath) == filepath.Clean(userRoot) {
  1751. //Initiate user folder (Initiaed in user object)
  1752. userinfo.GetHomeDirectory()
  1753. } else {
  1754. //Folder not exists
  1755. sendJSONResponse(w, "{\"error\":\"Folder not exists\"}")
  1756. return
  1757. }
  1758. }
  1759. if sortMode == "" {
  1760. sortMode = "default"
  1761. }
  1762. //Check for really special exception in where the path contains [ or ] which cannot be handled via Golang Glob function
  1763. files, _ := system_fs_specialGlob(filepath.Clean(realpath) + "/*")
  1764. var parsedFilelist []fs.FileData
  1765. for _, v := range files {
  1766. if showHidden != "true" && filepath.Base(v)[:1] == "." {
  1767. //Skipping hidden files
  1768. continue
  1769. }
  1770. rawsize := fs.GetFileSize(v)
  1771. modtime, _ := fs.GetModTime(v)
  1772. thisFile := fs.FileData{
  1773. Filename: filepath.Base(v),
  1774. Filepath: currentDir + filepath.Base(v),
  1775. Realpath: v,
  1776. IsDir: IsDir(v),
  1777. Filesize: rawsize,
  1778. Displaysize: fs.GetFileDisplaySize(rawsize, 2),
  1779. ModTime: modtime,
  1780. IsShared: shareManager.FileIsShared(v),
  1781. }
  1782. parsedFilelist = append(parsedFilelist, thisFile)
  1783. }
  1784. //Sort the filelist
  1785. if sortMode == "default" {
  1786. //Sort by name, convert filename to window sorting methods
  1787. sort.Slice(parsedFilelist, func(i, j int) bool {
  1788. return strings.ToLower(parsedFilelist[i].Filename) < strings.ToLower(parsedFilelist[j].Filename)
  1789. })
  1790. } else if sortMode == "reverse" {
  1791. //Sort by reverse name
  1792. sort.Slice(parsedFilelist, func(i, j int) bool {
  1793. return strings.ToLower(parsedFilelist[i].Filename) > strings.ToLower(parsedFilelist[j].Filename)
  1794. })
  1795. } else if sortMode == "smallToLarge" {
  1796. sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].Filesize < parsedFilelist[j].Filesize })
  1797. } else if sortMode == "largeToSmall" {
  1798. sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].Filesize > parsedFilelist[j].Filesize })
  1799. } else if sortMode == "mostRecent" {
  1800. sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].ModTime > parsedFilelist[j].ModTime })
  1801. } else if sortMode == "leastRecent" {
  1802. sort.Slice(parsedFilelist, func(i, j int) bool { return parsedFilelist[i].ModTime < parsedFilelist[j].ModTime })
  1803. }
  1804. jsonString, _ := json.Marshal(parsedFilelist)
  1805. sendJSONResponse(w, string(jsonString))
  1806. }
  1807. //Handle getting a hash from a given contents in the given path
  1808. func system_fs_handleDirHash(w http.ResponseWriter, r *http.Request) {
  1809. currentDir, err := mv(r, "dir", true)
  1810. if err != nil {
  1811. sendErrorResponse(w, "Invalid dir given")
  1812. return
  1813. }
  1814. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  1815. if err != nil {
  1816. sendErrorResponse(w, "User not logged in")
  1817. return
  1818. }
  1819. rpath, err := userinfo.VirtualPathToRealPath(currentDir)
  1820. if err != nil {
  1821. sendErrorResponse(w, "Invalid dir given")
  1822. return
  1823. }
  1824. //Get a list of files in this directory
  1825. currentDir = filepath.ToSlash(filepath.Clean(rpath)) + "/"
  1826. filesInDir, err := system_fs_specialGlob(currentDir + "*")
  1827. if err != nil {
  1828. sendErrorResponse(w, err.Error())
  1829. return
  1830. }
  1831. filenames := []string{}
  1832. for _, file := range filesInDir {
  1833. if len(filepath.Base(file)) > 0 && string([]rune(filepath.Base(file))[0]) != "." {
  1834. //Ignore hidden files
  1835. filenames = append(filenames, filepath.Base(file))
  1836. }
  1837. }
  1838. sort.Strings(filenames)
  1839. //Build a hash base on the filelist
  1840. h := sha256.New()
  1841. h.Write([]byte(strings.Join(filenames, ",")))
  1842. sendTextResponse(w, hex.EncodeToString((h.Sum(nil))))
  1843. }
  1844. /*
  1845. File zipping and unzipping functions
  1846. */
  1847. //Handle all zip related API
  1848. func system_fs_zipHandler(w http.ResponseWriter, r *http.Request) {
  1849. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  1850. if err != nil {
  1851. sendErrorResponse(w, err.Error())
  1852. return
  1853. }
  1854. opr, err := mv(r, "opr", true)
  1855. if err != nil {
  1856. sendErrorResponse(w, "Invalid opr or opr not defined")
  1857. return
  1858. }
  1859. vsrc, _ := mv(r, "src", true)
  1860. if vsrc == "" {
  1861. sendErrorResponse(w, "Invalid src paramter")
  1862. return
  1863. }
  1864. vdest, _ := mv(r, "dest", true)
  1865. rdest := ""
  1866. //Convert source path from JSON string to object
  1867. virtualSourcePaths := []string{}
  1868. err = json.Unmarshal([]byte(vsrc), &virtualSourcePaths)
  1869. if err != nil {
  1870. sendErrorResponse(w, err.Error())
  1871. return
  1872. }
  1873. //Check each of the path
  1874. realSourcePaths := []string{}
  1875. for _, vpath := range virtualSourcePaths {
  1876. thisrpath, err := userinfo.VirtualPathToRealPath(vpath)
  1877. if err != nil || !fileExists(thisrpath) {
  1878. sendErrorResponse(w, "File not exists: "+vpath)
  1879. return
  1880. }
  1881. realSourcePaths = append(realSourcePaths, thisrpath)
  1882. }
  1883. ///Convert dest to real if given
  1884. if vdest != "" {
  1885. realdest, _ := userinfo.VirtualPathToRealPath(vdest)
  1886. rdest = realdest
  1887. }
  1888. //This function will be deprecate soon in ArozOS 1.120
  1889. log.Println("*DEPRECATE* zipHandler will be deprecating soon! Please use fileOpr endpoint")
  1890. if opr == "zip" {
  1891. //Check if destination location exists
  1892. if rdest == "" || !fileExists(filepath.Dir(rdest)) {
  1893. sendErrorResponse(w, "Invalid dest location")
  1894. return
  1895. }
  1896. //OK. Create the zip at the desired location
  1897. err := fs.ArozZipFile(realSourcePaths, rdest, false)
  1898. if err != nil {
  1899. sendErrorResponse(w, err.Error())
  1900. return
  1901. }
  1902. sendOK(w)
  1903. } else if opr == "tmpzip" {
  1904. //Zip to tmp folder
  1905. userTmpFolder, _ := userinfo.VirtualPathToRealPath("tmp:/")
  1906. filename := Int64ToString(GetUnixTime()) + ".zip"
  1907. rdest := filepath.ToSlash(filepath.Clean(userTmpFolder)) + "/" + filename
  1908. log.Println(realSourcePaths, rdest)
  1909. err := fs.ArozZipFile(realSourcePaths, rdest, false)
  1910. if err != nil {
  1911. sendErrorResponse(w, err.Error())
  1912. return
  1913. }
  1914. //Send the tmp filename to the user
  1915. sendTextResponse(w, "tmp:/"+filename)
  1916. } else if opr == "inspect" {
  1917. } else if opr == "unzip" {
  1918. }
  1919. }
  1920. //Translate path from and to virtual and realpath
  1921. func system_fs_handlePathTranslate(w http.ResponseWriter, r *http.Request) {
  1922. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  1923. if err != nil {
  1924. sendErrorResponse(w, err.Error())
  1925. return
  1926. }
  1927. path, err := mv(r, "path", false)
  1928. if err != nil {
  1929. sendErrorResponse(w, "Invalid path given")
  1930. return
  1931. }
  1932. rpath, err := userinfo.VirtualPathToRealPath(path)
  1933. if err != nil {
  1934. //Try to convert it to virtualPath
  1935. vpath, err := userinfo.RealPathToVirtualPath(path)
  1936. if err != nil {
  1937. sendErrorResponse(w, "Unknown path given")
  1938. } else {
  1939. jsonstring, _ := json.Marshal(vpath)
  1940. sendJSONResponse(w, string(jsonstring))
  1941. }
  1942. } else {
  1943. abrpath, _ := filepath.Abs(rpath)
  1944. jsonstring, _ := json.Marshal([]string{rpath, filepath.ToSlash(abrpath)})
  1945. sendJSONResponse(w, string(jsonstring))
  1946. }
  1947. }
  1948. //Handle cache rendering with websocket pipeline
  1949. func system_fs_handleCacheRender(w http.ResponseWriter, r *http.Request) {
  1950. userinfo, _ := userHandler.GetUserInfoFromRequest(w, r)
  1951. vpath, err := mv(r, "folder", false)
  1952. if err != nil {
  1953. sendErrorResponse(w, "Invalid folder paramter")
  1954. return
  1955. }
  1956. //Convert vpath to realpath
  1957. rpath, err := userinfo.VirtualPathToRealPath(vpath)
  1958. if err != nil {
  1959. sendErrorResponse(w, err.Error())
  1960. return
  1961. }
  1962. //Perform cache rendering
  1963. thumbRenderHandler.HandleLoadCache(w, r, rpath)
  1964. }
  1965. //Handle file thumbnail caching
  1966. func system_fs_handleFolderCache(w http.ResponseWriter, r *http.Request) {
  1967. userinfo, _ := userHandler.GetUserInfoFromRequest(w, r)
  1968. vfolderpath, err := mv(r, "folder", false)
  1969. if err != nil {
  1970. sendErrorResponse(w, "folder not defined")
  1971. return
  1972. }
  1973. rpath, err := userinfo.VirtualPathToRealPath(vfolderpath)
  1974. if err != nil {
  1975. sendErrorResponse(w, err.Error())
  1976. return
  1977. }
  1978. thumbRenderHandler.BuildCacheForFolder(rpath)
  1979. sendOK(w)
  1980. }
  1981. //Handle setting and loading of file permission on Linux
  1982. func system_fs_handleFilePermission(w http.ResponseWriter, r *http.Request) {
  1983. file, err := mv(r, "file", true)
  1984. if err != nil {
  1985. sendErrorResponse(w, "Invalid file")
  1986. return
  1987. }
  1988. //Translate the file to real path
  1989. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  1990. if err != nil {
  1991. sendErrorResponse(w, "User not logged in")
  1992. return
  1993. }
  1994. rpath, err := userinfo.VirtualPathToRealPath(file)
  1995. if err != nil {
  1996. sendErrorResponse(w, err.Error())
  1997. return
  1998. }
  1999. newMode, _ := mv(r, "mode", true)
  2000. if newMode == "" {
  2001. //Read the file mode
  2002. //Check if the file exists
  2003. if !fileExists(rpath) {
  2004. sendErrorResponse(w, "File not exists!")
  2005. return
  2006. }
  2007. //Read the file permission
  2008. filePermission, err := fsp.GetFilePermissions(rpath)
  2009. if err != nil {
  2010. sendErrorResponse(w, err.Error())
  2011. return
  2012. }
  2013. //Send the file permission to client
  2014. js, _ := json.Marshal(filePermission)
  2015. sendJSONResponse(w, string(js))
  2016. } else {
  2017. //Set the file mode
  2018. //Check if the file exists
  2019. if !fileExists(rpath) {
  2020. sendErrorResponse(w, "File not exists!")
  2021. return
  2022. }
  2023. //Check if windows. If yes, ignore this request
  2024. if runtime.GOOS == "windows" {
  2025. sendErrorResponse(w, "Windows host not supported")
  2026. return
  2027. }
  2028. //Check if this user has permission to change the file permission
  2029. //Aka user must be 1. This is his own folder or 2. Admin
  2030. fsh, _ := userinfo.GetFileSystemHandlerFromVirtualPath(file)
  2031. if fsh.Hierarchy == "user" {
  2032. //Always ok as this is owned by the user
  2033. } else if fsh.Hierarchy == "public" {
  2034. //Require admin
  2035. if userinfo.IsAdmin() == false {
  2036. sendErrorResponse(w, "Permission Denied")
  2037. return
  2038. }
  2039. } else {
  2040. //Not implemeneted. Require admin
  2041. if userinfo.IsAdmin() == false {
  2042. sendErrorResponse(w, "Permission Denied")
  2043. return
  2044. }
  2045. }
  2046. //Be noted that if the system is not running in sudo mode,
  2047. //File permission change might not works.
  2048. err := fsp.SetFilePermisson(rpath, newMode)
  2049. if err != nil {
  2050. sendErrorResponse(w, err.Error())
  2051. return
  2052. } else {
  2053. sendOK(w)
  2054. }
  2055. }
  2056. }
  2057. //Check if the given filepath is and must inside the given directory path.
  2058. //You can pass both as relative
  2059. func system_fs_checkFileInDirectory(filesourcepath string, directory string) bool {
  2060. filepathAbs, err := filepath.Abs(filesourcepath)
  2061. if err != nil {
  2062. return false
  2063. }
  2064. directoryAbs, err := filepath.Abs(directory)
  2065. if err != nil {
  2066. return false
  2067. }
  2068. //Check if the filepathabs contain directoryAbs
  2069. if strings.Contains(filepathAbs, directoryAbs) {
  2070. return true
  2071. } else {
  2072. return false
  2073. }
  2074. }
  2075. //Clear the old files inside the tmp file
  2076. func system_fs_clearOldTmpFiles() {
  2077. filesToBeDelete := []string{}
  2078. tmpAbs, _ := filepath.Abs(*tmp_directory)
  2079. filepath.Walk(*tmp_directory, func(path string, info os.FileInfo, err error) error {
  2080. if filepath.Base(path) != "aofs.db" && filepath.Base(path) != "aofs.db.lock" {
  2081. //Check if root folders. Do not delete root folders
  2082. parentAbs, _ := filepath.Abs(filepath.Dir(path))
  2083. if tmpAbs == parentAbs {
  2084. //Root folder. Do not remove
  2085. return nil
  2086. }
  2087. //Get its modification time
  2088. modTime, err := fs.GetModTime(path)
  2089. if err != nil {
  2090. return nil
  2091. }
  2092. //Check if mod time is more than 24 hours ago
  2093. if time.Now().Unix()-modTime > int64(*maxTempFileKeepTime) {
  2094. //Delete OK
  2095. filesToBeDelete = append(filesToBeDelete, path)
  2096. }
  2097. }
  2098. return nil
  2099. })
  2100. //Remove all files from the delete list
  2101. for _, fileToBeDelete := range filesToBeDelete {
  2102. os.RemoveAll(fileToBeDelete)
  2103. }
  2104. }