Add utime to luci.fs
[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 --- Set the last modification time  of given file path in Unix epoch format.
140 -- @param path  String containing the path of the file or directory to read
141 -- @param mtime Last modification timestamp
142 -- @param atime Last accessed timestamp
143 -- @return              0 in case of success nil on error
144 -- @return              String containing the error description (if any)
145 -- @return              Number containing the os specific errno (if any)
146 utime = posix.utime
147
148 --- Return the last element - usually the filename - from the given path with
149 -- the directory component stripped.
150 -- @class               function
151 -- @name                basename
152 -- @param path  String containing the path to strip
153 -- @return              String containing the base name of given path
154 -- @see                 dirname
155 basename = posix.basename
156
157 --- Return the directory component of the given path with the last element
158 -- stripped of.
159 -- @class               function
160 -- @name                dirname
161 -- @param path  String containing the path to strip
162 -- @return              String containing the directory component of given path
163 -- @see                 basename
164 dirname = posix.dirname
165
166 --- Return a table containing all entries of the specified directory.
167 -- @class               function
168 -- @name                dir
169 -- @param path  String containing the path of the directory to scan
170 -- @return              Table containing file and directory entries or nil on error
171 -- @return              String containing the error description on error
172 -- @return              Number containing the os specific errno on error
173 dir = posix.dir
174
175 --- Create a new directory, recursively on demand.
176 -- @param path          String with the name or path of the directory to create
177 -- @param recursive     Create multiple directory levels (optional, default is true)
178 -- @return                      Number with the return code, 0 on sucess or nil on error
179 -- @return                      String containing the error description on error
180 -- @return                      Number containing the os specific errno on error
181 function mkdir(path, recursive)
182         if recursive then
183                 local base = "."
184
185                 if path:sub(1,1) == "/" then
186                         base = ""
187                         path = path:gsub("^/+","")
188                 end
189
190                 for elem in path:gmatch("([^/]+)/*") do
191                         base = base .. "/" .. elem
192
193                         local stat = posix.stat( base )
194
195                         if not stat then
196                                 local stat, errmsg, errno = posix.mkdir( base )
197
198                                 if type(stat) ~= "number" or stat ~= 0 then
199                                         return stat, errmsg, errno
200                                 end
201                         else
202                                 if stat.type ~= "directory" then
203                                         return nil, base .. ": File exists", 17
204                                 end
205                         end
206                 end
207
208                 return 0
209         else
210                 return posix.mkdir( path )
211         end
212 end
213
214 --- Remove the given empty directory.
215 -- @class               function
216 -- @name                rmdir
217 -- @param path  String containing the path of the directory to remove
218 -- @return              Number with the return code, 0 on sucess or nil on error
219 -- @return              String containing the error description on error
220 -- @return              Number containing the os specific errno on error
221 rmdir = posix.rmdir
222
223 --- Get information about given file or directory.
224 -- @class               function
225 -- @name                stat
226 -- @param path  String containing the path of the directory to query
227 -- @return              Table containing file or directory properties or nil on error
228 -- @return              String containing the error description on error
229 -- @return              Number containing the os specific errno on error
230 stat = posix.stat
231
232 --- Set permissions on given file or directory.
233 -- @class               function
234 -- @name                chmod
235 -- @param path  String containing the path of the directory
236 -- @param perm  String containing the permissions to set ([ugoa][+-][rwx])
237 -- @return              Number with the return code, 0 on sucess or nil on error
238 -- @return              String containing the error description on error
239 -- @return              Number containing the os specific errno on error
240 chmod = posix.chmod
241
242 --- Create a hard- or symlink from given file (or directory) to specified target
243 -- file (or directory) path.
244 -- @class                       function
245 -- @name                        link
246 -- @param path1         String containing the source path to link
247 -- @param path2         String containing the destination path for the link
248 -- @param symlink       Boolean indicating wheather to create a symlink (optional)
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 link = posix.link
253
254 --- Remove the given file.
255 -- @class               function
256 -- @name                unlink
257 -- @param path  String containing the path of the file to remove
258 -- @return              Number with the return code, 0 on sucess or nil on error
259 -- @return              String containing the error description on error
260 -- @return              Number containing the os specific errno on error
261 unlink = posix.unlink
262
263 --- Retrieve target of given symlink.
264 -- @class               function
265 -- @name                readlink
266 -- @param path  String containing the path of the symlink to read
267 -- @return              String containing the link target or nil on error
268 -- @return              String containing the error description on error
269 -- @return              Number containing the os specific errno on error
270 readlink = posix.readlink