Добавлена проверка прав, чтобы не пытаться читать недоступный каталог.
[lua-filemanager.git] / www / cgi-bin / fs
1 #!/usr/bin/lua
2
3 local os = require "os"
4 local fs = require "nixio.fs"
5 local json = require "json"
6 local uci = require("uci")
7
8 local function is_in_dir(file, dir)
9   if file == dir then
10     return true
11   else   
12     return file:sub(1, #dir) == dir
13   end  
14 end
15
16 local function rm(item)
17   local ftype = fs.stat(item,"type")
18   if ftype == "reg" then
19     return fs.remove(item)
20   elseif ftype == "dir" then
21     local dir = fs.dir(item)
22     for file in dir do
23       if not rm(item..'/'..file) then
24         return false
25       end
26     end
27     return fs.rmdir(item)  
28   end
29 end
30
31 local function chmod(item,mode,recursive)
32   local result = fs.chmod(item,mode)
33   if result and recursive then
34     local dir = fs.dir(item)
35     if dir then
36       for file in dir do
37         local ftype = fs.stat(item..'/'..file,"type")
38         if ftype == "dir" then
39           result = chmod(item..'/'..file,mode,recursive)
40         elseif ftype == "reg" then
41           result = chmod(item..'/'..file,string.gsub(mode,"x","-"),false)  
42         end
43         if not result then
44           break
45         end  
46       end
47     end
48   end
49   return result
50 end
51
52 print("Content-type: text/html; charset=utf-8")
53 print("Cache-control: no-cache")
54 print("Pragma: no-cache")
55
56 -- prepare the browser for content:
57 print("\r")
58
59 local result
60
61 local http_headers = nixio.getenv()
62 local request=io.read("*all")
63
64 local params=json.decode(request)
65 local action=params["action"]
66
67 local u_c = uci.cursor()
68 local basepath = u_c.get("filemanager","config","basedir")
69
70 local path
71 local items
72 local item
73 local newItemPath
74 local newPath
75 local singleFilename
76 local content
77 local mode
78 local destination
79 local compressedFilename
80 local recursive
81 local folderName
82
83 local files
84 local fstat
85 local ftype
86 local basename
87 local realitem
88 local command
89
90 if action == "list" then
91
92   path = fs.realpath(basepath..'/'..params["path"])
93   
94   if path and is_in_dir(path,basepath) and fs.access(path,"r") then
95     files = {}
96     local rec
97     for name in fs.dir(path) do
98       basename=fs.realpath(path..'/'..name)
99       if basename then
100         fstat=fs.stat(fs.realpath(path..'/'..name))
101         if fstat["type"]=="reg" then
102           ftype="file"
103         elseif fstat["type"]=="dir" then
104           ftype="dir"
105         else
106           ftype=""
107         end      
108         if ftype then
109           rec={name=name,rights=fstat["modestr"],size=fstat["size"],type=ftype,date=os.date('%Y-%m-%d %H:%M:%S',fstat["mtime"])}
110           table.insert(files,rec)
111         end
112       end    
113     end
114     result = { result = files }
115   else
116     result = { result = {} }
117   end
118
119 elseif action == "rename" then
120
121   item = fs.realpath(basepath..'/'..params["item"])
122   newItemPath = fs.realpath(basepath..'/'..fs.dirname(params["newItemPath"]))..'/'..fs.basename(params["newItemPath"])
123
124   if is_in_dir(item,basepath) and is_in_dir(newItemPath,basepath) and item ~= basepath and newItemPath ~= basepath then
125     result = { result = { success=fs.rename(item,newItemPath), error="" } }
126   else
127     result = { result = { success=false, error="Invalid path request" } }
128   end
129
130 elseif action == "move" then
131
132   items = params["items"]
133   newPath = fs.realpath(basepath..'/'..params["newPath"])
134   
135   if is_in_dir(newPath,basepath) then
136
137     result = true
138
139     for key,item in pairs(items) do
140
141       item = fs.realpath(basepath..'/'..item)
142       basename = fs.basename(item)
143
144       if is_in_dir(item,basepath) and item ~= basepath then
145         result = fs.move(item,newPath.."/"..basename)
146         if not result then 
147           break
148         end
149       else
150         result = false
151         break
152       end
153       
154     end  
155
156     result = { result = { success=result, error="" } }
157
158   else
159
160     result = { result = { success=false, error="Invalid destination request" } }
161
162   end  
163
164 elseif action == "copy" then
165
166   items = params["items"]
167   newPath = fs.realpath(basepath..'/'..params["newPath"])
168   singleFilename = params["singleFilename"]
169   if singleFilename then
170     singleFilename = fs.basename(singleFilename)
171   end
172
173   if is_in_dir(newPath,basepath) then
174
175     result = true
176
177     for key,item in pairs(items) do
178
179       item = fs.realpath(basepath..'/'..item)
180       if singleFilename then
181         basename = singleFilename
182       else  
183         basename = fs.basename(item)
184       end
185
186       if is_in_dir(item,basepath) and item ~= basepath then
187         result = fs.copy(item,newPath.."/"..basename)
188         if not result then 
189           break
190         end
191       else
192         result = false
193         break
194       end
195
196     end  
197
198     result = { result = { success=result, error="" } }
199
200   else
201
202     result = { result = { success=false, error="Invalid destination request" } }
203
204   end  
205
206 elseif action == "remove" then
207
208   items = params["items"]
209
210   result = true
211
212   for key,item in pairs(items) do
213
214     item = fs.realpath(basepath..'/'..item)
215
216     if is_in_dir(item,basepath) and item ~= basepath then
217       result = rm(item)
218       if not result then 
219         break
220       end
221     else
222       result = false
223       break
224     end
225
226   end
227
228   result = { result = { success=result, error="" } }
229
230 elseif action == "getContent" then
231
232   item = fs.realpath(basepath..'/'..params["item"])
233   
234   if is_in_dir(item,basepath) and item ~= basepath then
235     content = fs.readfile(item)
236     result = { result = content }
237   else
238     result = { result = { success=false, error="Invalid path request" } }
239   end
240
241 elseif action == "edit" then
242
243   item = fs.realpath(basepath..'/'..params["item"])
244   content = params["content"]
245   
246   if is_in_dir(item,basepath) and item ~= basepath then
247     result = { result = { success=fs.writefile(item,content), error="" } }
248   else
249     result = { result = { success=false, error="Invalid path request" } }
250   end
251
252 elseif action == "createFolder" then
253
254   newPath = fs.realpath(basepath..'/'..fs.dirname(params["newPath"]))..'/'..fs.basename(params["newPath"])
255   
256   if is_in_dir(newPath,basepath) and newPath ~= basepath then
257     result = { result = { success=fs.mkdir(newPath), error="" } }
258   else
259     result = { result = { success=false, error="Invalid path request" } }
260   end
261
262 elseif action == "changePermissions" then
263
264   items = params["items"]
265   if params["perms"] then
266     mode = params["perms"]
267   else
268     mode = params["permsCode"]
269   end
270   
271   if mode then
272     
273     recursive = params["recursive"]
274
275     result = true
276
277     for key,item in pairs(items) do
278
279       item = fs.realpath(basepath..'/'..item)
280
281       if is_in_dir(item,basepath) and item ~= basepath then
282         result = chmod(item,mode,recursive)
283         if not result then 
284           break
285         end
286       else
287         result = false
288         break
289       end
290
291     end
292
293     result = { result = { success=result, error="" } }
294
295   else
296   
297     result = { result = { success=false, error="No permission requested" } }
298   
299   end
300
301 elseif action == "compress" then
302
303   items = params["items"]
304   destination = params["destination"]
305   compressedFilename = params["compressedFilename"]
306
307   newPath = fs.realpath(basepath..'/'..destination)..'/'..fs.basename(params["compressedFilename"])
308
309   result = true
310   files = ""
311
312   for key,item in pairs(items) do
313
314     realitem = fs.realpath(basepath..'/'..item)
315
316     if is_in_dir(realitem,basepath) and realitem ~= basepath then
317       item = item:match("/(.*)")
318       files = files.." "..item
319     else
320       result = false
321       break
322     end
323
324   end
325   
326   if files then
327
328     command = "cd "..basepath.."; zip -r "..newPath..files
329     os.execute(command)
330   
331   end
332
333   result = { result = { success=result, error="" } }
334
335 elseif action == "extract" then
336
337   item = fs.realpath(basepath..'/'..params["item"])
338   destination = params["destination"]
339   folderName = params["folderName"]
340
341   newPath = fs.realpath(basepath..'/'..destination)..'/'..fs.basename(params["folderName"])
342
343   result = true
344   files = ""
345
346   if is_in_dir(item,basepath) and is_in_dir(newPath,basepath) and item ~= basepath then
347     command = "unzip "..item.." -d "..newPath
348     os.execute(command)
349     result = { result = { success=true, error="" } }
350   else
351     result = { result = { success=false, error="Invalid path request" } }
352   end
353
354
355 else
356
357   result = { result = { success=false, error="Operation not impolemented yet" } }
358
359 end
360
361 print(json.encode(result))