libs/core: implement fs.isdirectory()
[project/luci.git] / libs / core / luasrc / fs.lua
1 --[[
2 LuCI - Filesystem tools
3
4 Description:
5 A module offering often needed filesystem manipulation functions
6
7 FileId:
8 $Id$
9
10 License:
11 Copyright 2008 Steven Barth <steven@midlink.org>
12
13 Licensed under the Apache License, Version 2.0 (the "License");
14 you may not use this file except in compliance with the License.
15 You may obtain a copy of the License at
16
17         http://www.apache.org/licenses/LICENSE-2.0
18
19 Unless required by applicable law or agreed to in writing, software
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
24
25 ]]--
26
27 local io    = require "io"
28 local os    = require "os"
29 local ltn12 = require "luci.ltn12"
30 local posix = require "posix"
31
32 local type  = type
33
34 --- LuCI filesystem library.
35 module "luci.fs"
36
37 --- Test for file access permission on given path.
38 -- @class               function
39 -- @name                access
40 -- @param str   String value containing the path
41 -- @return              Number containing the return code, 0 on sucess or nil on error
42 -- @return              String containing the error description (if any)
43 -- @return              Number containing the os specific errno (if any)
44 access = posix.access
45
46 --- Evaluate given shell glob pattern and return a table containing all matching
47 -- file and directory entries.
48 -- @class                       function
49 -- @name                        glob
50 -- @param filename      String containing the path of the file to read
51 -- @return                      Table containing file and directory entries or nil if no matches
52 -- @return                      String containing the error description (if no matches)
53 -- @return                      Number containing the os specific errno (if no matches)
54 glob = posix.glob
55
56 --- Checks wheather the given path exists and points to a regular file.
57 -- @param filename      String containing the path of the file to test
58 -- @return                      Boolean indicating wheather given path points to regular file
59 function isfile(filename)
60         return posix.stat(filename, "type") == "regular"
61 end
62
63 --- Checks wheather the given path exists and points to a directory.
64 -- @param dirname       String containing the path of the directory to test
65 -- @return                      Boolean indicating wheather given path points to directory
66 function isdirectory(dirname)
67         return posix.stat(dirname, "type") == "directory"
68 end
69
70 --- Read the whole content of the given file into memory.
71 -- @param filename      String containing the path of the file to read
72 -- @return                      String containing the file contents or nil on error
73 -- @return                      String containing the error message on error
74 function readfile(filename)
75         local fp, err = io.open(filename)
76
77         if fp == nil then
78                 return nil, err
79         end
80
81         local data = fp:read("*a")
82         fp:close()
83         return data
84 end
85
86 --- Write the contents of given string to given file.
87 -- @param filename      String containing the path of the file to read
88 -- @param data          String containing the data to write
89 -- @return                      Boolean containing true on success or nil on error
90 -- @return                      String containing the error message on error
91 function writefile(filename, data)
92         local fp, err = io.open(filename, "w")
93
94         if fp == nil then
95                 return nil, err
96         end
97
98         fp:write(data)
99         fp:close()
100
101         return true
102 end
103
104 --- Copies a file.
105 -- @param source        Source file
106 -- @param dest          Destination
107 -- @return                      Boolean containing true on success or nil on error
108 function copy(source, dest)
109         return ltn12.pump.all(
110                 ltn12.source.file(io.open(source)),
111                 ltn12.sink.file(io.open(dest, "w"))
112         )
113 end
114
115 --- Renames a file.
116 -- @param source        Source file
117 -- @param dest          Destination
118 -- @return                      Boolean containing true on success or nil on error
119 function rename(source, dest)
120         local stat, err, code = os.rename(source, dest)
121         if code == 18 then
122                 stat, err, code = copy(source, dest)
123                 if stat then
124                         stat, err, code = unlink(source)
125                 end
126         end
127         return stat, err, code
128 end
129
130 --- Get the last modification time of given file path in Unix epoch format.
131 -- @param path  String containing the path of the file or directory to read
132 -- @return              Number containing the epoch time or nil on error
133 -- @return              String containing the error description (if any)
134 -- @return              Number containing the os specific errno (if any)
135 function mtime(path)
136         return posix.stat(path, "mtime")
137 end
138
139 --- Return the last element - usually the filename - from the given path with
140 -- the directory component stripped.
141 -- @class               function
142 -- @name                basename
143 -- @param path  String containing the path to strip
144 -- @return              String containing the base name of given path
145 -- @see                 dirname
146 basename = posix.basename
147
148 --- Return the directory component of the given path with the last element
149 -- stripped of.
150 -- @class               function
151 -- @name                dirname
152 -- @param path  String containing the path to strip
153 -- @return              String containing the directory component of given path
154 -- @see                 basename
155 dirname = posix.dirname
156
157 --- Return a table containing all entries of the specified directory.
158 -- @class               function
159 -- @name                dir
160 -- @param path  String containing the path of the directory to scan
161 -- @return              Table containing file and directory entries or nil on error
162 -- @return              String containing the error description on error
163 -- @return              Number containing the os specific errno on error
164 dir = posix.dir
165
166 --- Create a new directory, recursively on demand.
167 -- @param path          String with the name or path of the directory to create
168 -- @param recursive     Create multiple directory levels (optional, default is true)
169 -- @return                      Number with the return code, 0 on sucess or nil on error
170 -- @return                      String containing the error description on error
171 -- @return                      Number containing the os specific errno on error
172 function mkdir(path, recursive)
173         if recursive then
174                 local base = "."
175
176                 if path:sub(1,1) == "/" then
177                         base = ""
178                         path = path:gsub("^/+","")
179                 end
180
181                 for elem in path:gmatch("([^/]+)/*") do
182                         base = base .. "/" .. elem
183
184                         local stat = posix.stat( base )
185
186                         if not stat then
187                                 local stat, errmsg, errno = posix.mkdir( base )
188
189                                 if type(stat) ~= "number" or stat ~= 0 then
190                                         return stat, errmsg, errno
191                                 end
192                         else
193                                 if stat.type ~= "directory" then
194                                         return nil, base .. ": File exists", 17
195                                 end
196                         end
197                 end
198
199                 return 0
200         else
201                 return posix.mkdir( path )
202         end
203 end
204
205 --- Remove the given empty directory.
206 -- @class               function
207 -- @name                rmdir
208 -- @param path  String containing the path of the directory to remove
209 -- @return              Number with the return code, 0 on sucess or nil on error
210 -- @return              String containing the error description on error
211 -- @return              Number containing the os specific errno on error
212 rmdir = posix.rmdir
213
214 --- Get information about given file or directory.
215 -- @class               function
216 -- @name                stat
217 -- @param path  String containing the path of the directory to query
218 -- @return              Table containing file or directory properties or nil on error
219 -- @return              String containing the error description on error
220 -- @return              Number containing the os specific errno on error
221 stat = posix.stat
222
223 --- Set permissions on given file or directory.
224 -- @class               function
225 -- @name                chmod
226 -- @param path  String containing the path of the directory
227 -- @param perm  String containing the permissions to set ([ugoa][+-][rwx])
228 -- @return              Number with the return code, 0 on sucess or nil on error
229 -- @return              String containing the error description on error
230 -- @return              Number containing the os specific errno on error
231 chmod = posix.chmod
232
233 --- Create a hard- or symlink from given file (or directory) to specified target
234 -- file (or directory) path.
235 -- @class                       function
236 -- @name                        link
237 -- @param path1         String containing the source path to link
238 -- @param path2         String containing the destination path for the link
239 -- @param symlink       Boolean indicating wheather to create a symlink (optional)
240 -- @return                      Number with the return code, 0 on sucess or nil on error
241 -- @return                      String containing the error description on error
242 -- @return                      Number containing the os specific errno on error
243 link = posix.link
244
245 --- Remove the given file.
246 -- @class               function
247 -- @name                unlink
248 -- @param path  String containing the path of the file to remove
249 -- @return              Number with the return code, 0 on sucess or nil on error
250 -- @return              String containing the error description on error
251 -- @return              Number containing the os specific errno on error
252 unlink = posix.unlink
253
254 --- Retrieve target of given symlink.
255 -- @class               function
256 -- @name                readlink
257 -- @param path  String containing the path of the symlink to read
258 -- @return              String containing the link target or nil on error
259 -- @return              String containing the error description on error
260 -- @return              Number containing the os specific errno on error
261 readlink = posix.readlink