summaryrefslogtreecommitdiff
path: root/src/sh/file.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/sh/file.cc')
-rw-r--r--src/sh/file.cc367
1 files changed, 367 insertions, 0 deletions
diff --git a/src/sh/file.cc b/src/sh/file.cc
new file mode 100644
index 0000000..3d885c5
--- /dev/null
+++ b/src/sh/file.cc
@@ -0,0 +1,367 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <sh/htc.h>
21#include <hdb/buffer.h>
22#include <mt/dates.h>
23#include <dirent.h>
24#include <sys/stat.h>
25
26const mstring sdot=".",sdots="..";
27
28///////////////////////////////////////////////////////////////////
29
30inline void stat(struct stat& fs,Env& env,const sref& path) throw(merror_t) {
31 if(::stat(DocPath(env,path).c_str(),&fs)<0)
32 THROW("htc: could not stat "<<path<<" - not found");
33}
34
35///////////////////////////////////////////////////////////////////
36
37TOK_IMPL(remfile) {
38 mstring path=DocPath(env,env[0]);
39 if(remove(path.c_str())<0) THROW("htc: Could not remove "<<path);
40}
41
42TOK_IMPL(renfile) {
43 mstring oldpath=DocPath(env,env[0]),newpath=DocPath(env,env[1]);
44 if(rename(oldpath.c_str(),newpath.c_str())<0)
45 THROW("htc: Could not rename "<<oldpath<<" to "<<newpath);
46}
47
48TOK_IMPL(filesafe) {
49 static const charset fsafe=cset_alphareal|'_';
50 mstring file=env[0];
51 int pos=file.rfind('/'); if(pos>=0) file=file.past(pos,1);
52 pos=file.rfind('\\'); if(pos>=0) file=file.past(pos,1);
53 while((pos=file.find(sdots))>=0) file.erase(pos,2);
54 mstring acc;
55 for(int i=0;i<file.size();i++) if(fsafe.test(file[i])) acc.append(1,file[i]);
56 out<<acc;
57}
58
59///////////////////////////////////////////////////////////////////
60
61TOK_IMPL(seturi) {
62 Req(env)->uri=env[0];
63}
64
65TOK_IMPL(uri) {
66 out<<Req(env)->uri;
67}
68
69TOK_IMPL(pwd) {
70 out<<Req(env)->uri.left_last('/');
71}
72
73TOK_IMPL(npwd) {
74 mstring s=Req(env)->uri.left_last('/');
75 for(int i=0;i<MAXLANG;i++) {
76 if(s.past_first('/').left_first('/')==LANG[i]) {
77 s=s.past_first('/').right_first('/');
78 break;
79 }
80 }
81 out<<s;
82}
83
84TOK_IMPL(home) {
85 if(Req(env)->htc()->docroot.nempty())
86 THROW("htc: home only works in absolute file mode");
87 out<<htchome();
88}
89
90///////////////////////////////////////////////////////////////////
91
92TOK_IMPL(load) {
93 mstring name=env.parg(-1),uri=env.URI(env[0]),path=DocPath(env,uri);
94 if(name.nempty()) LoadBuffer(Reference(*env.toks,name,uri,1)->data,path);
95 else { mstring buffer; LoadBuffer(buffer,path); out<<buffer; }
96}
97
98TOK_IMPL(open) {
99 mstring name=env[0],uri=env.URI(env[1]),path=DocPath(env,uri);
100 dbref_t* ref=DBRef(*env.toks,env[0],ms_empty,tok_t::PRIVATE,1);
101 ref->db.Open(path,atoi(env.parg(-1)));
102}
103
104TOK_IMPL(save) {
105 mstring path=DocPath(env,env[0]),var=env[1];
106 int prot=atoi(env.parg(2)); if(!prot) prot=0600;
107 tok_t* p=env.toks->get(var);
108 if(!p) THROW("htc: "<<var<<": no such variable");
109 if(p->is_reference()) SaveBuffer(((reference_t*)p)->data,path,prot);
110 else if(p->is_dbref()) ((dbref_t*)p)->db.Saveas(path,prot);
111 else SaveBuffer(p->body,path,prot);
112}
113
114TOK_IMPL(dbmod) {
115 dbref_t* p=(dbref_t*)env.toks->get(env[0]);
116 if(!p&&!p->is_dbref()) THROW("htc: "<<env[0]<<": no such database");
117 out<<p->db.Lastmod();
118}
119
120///////////////////////////////////////////////////////////////////
121
122static void Run(mstream& out,Env& env,const mstring& path) throw(merror_t) {
123 mstring buffer;
124 LoadBuffer(buffer,path);
125 env.parse(out,buffer);
126}
127
128TOK_IMPL(include) {
129 mstring cwd=env.URI(env[0]),path=DocPath(env,cwd);
130 if(!env.glob_find(cwd)) {
131 env.toks->add(new tok_t(cwd,ms_empty,tok_t::CONSTANT|tok_t::PRIVATE),0,1);
132 mstream m;
133 Env e(env,env.mod,cwd);
134 Run(m,e,path);
135 }
136}
137
138TOK_IMPL(parse) {
139 mstring cwd=env.URI(env[0]),path=DocPath(env,cwd);
140 Env e(env,env.mod,cwd);
141 Run(out,e,path);
142}
143
144TOK_IMPL(parse_private) {
145 mstring cwd=env.URI(env[0]),path=DocPath(env,cwd);
146 Env e(env,XPRIVATE,cwd);
147 Run(out,e,path);
148}
149
150TOK_IMPL(parse_public) {
151 mstring cwd=env.URI(env[0]),path=DocPath(env,cwd);
152 Env e(env,XPUBLIC,cwd);
153 Run(out,e,path);
154}
155
156///////////////////////////////////////////////////////////////////
157
158TOK_IMPL(dirent) {
159 mstring uri=env.URI(env[0]);
160 sref uribase=uri.leftand_last('/'),ext=uri.adv(uribase);
161 mstring dirpath=DocPath(env,uribase);
162 DIR* dir=opendir(dirpath.c_str());
163 if(dir) {
164 dirent* p;
165 while((p=readdir(dir))!=0) {
166 sref name(p->d_name);
167 if(name.empty()||name==sdot||name==sdots) continue;
168 if(ext.empty()||name.right(-ext.size()-1)==ext) out<<uribase<<name<<"\n";
169 }
170 closedir(dir);
171 }
172}
173
174TOK_IMPL(dirmod) {
175 struct stat fs;
176 if(::stat(DocPath(env,env[0]).c_str(),&fs)>=0) out<<fs.st_mode;
177 else out<<(int)0;
178}
179
180TOK_IMPL(dirmtime) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_mtime; }
181TOK_IMPL(diruid) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_uid; }
182TOK_IMPL(dirgid) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_gid; }
183TOK_IMPL(filesize) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_size; }
184
185TOK_IMPL(setperm) {
186 mstring path=DocPath(env,env[0]);
187 if(chmod(path.c_str(),atoi(env[1]))<0)
188 THROW("htc: could not set file permission for "<<path);
189}
190
191///////////////////////////////////////////////////////////////////
192
193void envAddFile(tokmap& T)
194{
195 TOK_ADD(remfile,"x",tok_t::SYSONLY,
196 "%Remove file\n"
197 "%Syntax: \\remfile{uri}\n"
198 );
199 TOK_ADD(renfile,"xx",tok_t::SYSONLY,
200 "%Rename file\n"
201 "%Syntax: \\renfile{olduri}{newuri}\n"
202 );
203 TOK_ADD(filesafe,"x",tok_t::PUBLIC,
204 "%Transform uri to something safe to save\n"
205 "%Syntax: \\filesafe{uri}\n"
206 "%\n"
207 "%Basically removes eventual path information and\n"
208 "%odd characters.\n"
209 );
210
211 ////////////////////////////////////////////////////////
212
213 TOK_ADD(seturi,"x",tok_t::SYSONLY,
214 "%Set current uri of current request\n"
215 "%Syntax: \\seturi\n"
216 "%\n"
217 "%Always points to a (virtual) uri.\n"
218 );
219 TOK_ADD(uri,"",tok_t::PUBLIC,
220 "%uri of current request\n"
221 "%Syntax: \\uri\n"
222 "%\n"
223 "%Always points to a (virtual) uri.\n"
224 );
225 TOK_ADD(pwd,"",tok_t::PUBLIC,
226 "%uri/directory of current request\n"
227 "%Syntax: \\pwd\n"
228 "%\n"
229 "%Always points to a (virtual) directory, and never contain any\n"
230 "%trailing slashes.\n"
231 );
232 TOK_ADD(npwd,"",tok_t::PUBLIC,
233 "%uri/directory of current request, without language reference\n"
234 "%Syntax: \\npwd\n"
235 "%\n"
236 "%Always points to a (virtual) directory, and never contain any\n"
237 "%trailing slashes.\n"
238 );
239 TOK_ADD(home,"",tok_t::PRIVATE,
240 "%Home directory\n"
241 "%Syntax: \\home\n"
242 "%\n"
243 "%Only works in absolute path mode, i.e. when no docroot is set.\n"
244 );
245
246 ////////////////////////////////////////////////////////
247
248 TOK_ADD(load,"?x",tok_t::PRIVATE,
249 "%Load file directly to output or to variable\n"
250 "%Syntax: \\load<varname>{uri}\n"
251 );
252 TOK_ADD(open,"xx?",tok_t::SYSONLY,
253 "%Open database to variable\n"
254 "%Syntax: \\load{varname}{uri}<update>\n"
255 "%\n"
256 "%If update is true, the database is opened for reading\n"
257 "%and writing. NOTE that all updates are syncronous and\n"
258 "%instantly - saves or locks are not needed.\n"
259 );
260 TOK_ADD(save,"xx?",tok_t::SYSONLY,
261 "%Save variable to file\n"
262 "%Syntax: \\save{uri}{varname}<prot>\n"
263 "%\n"
264 "%If the variable points to a reference object, the\n"
265 "%reference is saved. If it points to a database,\n"
266 "%the database is saved. For globals and functions,\n"
267 "%the body is saved.\n"
268 "%\n"
269 "%The optional prot argument is a (base 10) integer\n"
270 "%defining the creation mode mask (unix).\n"
271 );
272 TOK_ADD(dbmod,"x",tok_t::PUBLIC,
273 "%Get modification time of open database\n"
274 "%Syntax: \\dbmod{var}\n"
275 );
276
277 ////////////////////////////////////////////////////////
278
279 TOK_ADD(include,"x",tok_t::PRIVATE,
280 "%Include file in current running mode\n"
281 "%Syntax: \\include{uri}\n"
282 "%\n"
283 "%The file is loaded and evaluated, but produces no output\n"
284 "%Any uri can only be included once, so it is safe to use\n"
285 "%include as a precondition.\n"
286 "%\n"
287 "%NOTE that files parsed this way must be known to\n"
288 "%the super-user in order not to create a security hole -\n"
289 "%especially since this command is open in private mode also.\n"
290 );
291
292 TOK_ADD(parse,"x",tok_t::SYSONLY,
293 "%Parse file in current running mode\n"
294 "%Syntax: \\parse{uri}\n"
295 "%\n"
296 "%The file is loaded and evaluated to output.\n"
297 "%\n"
298 "%NOTE that files parsed this way must be known to\n"
299 "%the super-user in order not to create a security hole.\n"
300 );
301
302 TOK_ADD(parse_private,"x",tok_t::PRIVATE,
303 "%Parse file in private mode\n"
304 "%Syntax: \\parse.private{uri}\n"
305 "%\n"
306 "%The file is loaded and evaluated to output.\n"
307 "%\n"
308 "%System-mode commands are silently ignored.\n"
309 );
310
311 TOK_ADD(parse_public,"x",tok_t::PRIVATE,
312 "%Parse file in public mode\n"
313 "%Syntax: \\parse.public{uri}\n"
314 "%\n"
315 "%The file is loaded and evaluated to output.\n"
316 "%\n"
317 "%System/Private mode commands are silently ignored.\n"
318 );
319
320 ////////////////////////////////////////////////////////
321
322 TOK_ADD(dirent,"x",tok_t::SYSONLY,
323 "%Collect directory entries\n"
324 "%Syntax: \\dirent{uri/match}\n"
325 "%\n"
326 "%An argument of anydir/ collects all files in anydir.\n"
327 "%An argument of anydir/.ext collects all files ending with .ext\n"
328 "%\n"
329 "%Note that an argument of anydir collects files in the parent\n"
330 "%directory of anydir which end whith anydir, which probably is\n"
331 "%not what you want. Trailing slashes are important.\n"
332 );
333 TOK_ADD(dirmod,"x",tok_t::SYSONLY,
334 "%Return file mode of uri\n"
335 "%Syntax: \\dirmod{uri}\n"
336 "%\n"
337 "%dirmod uses the unix stat function.\n"
338 "%On failure to read, returns zero.\n"
339 );
340 TOK_ADD(dirmtime,"x",tok_t::SYSONLY,
341 "%Return modification time of uri\n"
342 "%Syntax: \\dirmtime{uri}\n"
343 );
344 TOK_ADD(diruid,"x",tok_t::SYSONLY,
345 "%Return UNIX uid of uri\n"
346 "%Syntax: \\diruid{uri}\n"
347 "%\n"
348 "%Note that the UNIX uid is different from the HTC one.\n"
349 );
350 TOK_ADD(dirgid,"x",tok_t::SYSONLY,
351 "%Return UNIX gid of uri\n"
352 "%Syntax: \\dirgid{uri}\n"
353 "%\n"
354 "%Note that the UNIX gid is different from the HTC one.\n"
355 );
356 TOK_ADD(filesize,"x",tok_t::SYSONLY,
357 "%Return filesize of uri\n"
358 "%Syntax: \\filesize{uri}\n"
359 );
360 TOK_ADD(setperm,"xx",tok_t::SYSONLY,
361 "%Set file permissions of uri\n"
362 "%Syntax: \\setperm{uri}{mode}\n"
363 "%\n"
364 "%Mode is an integer bitmask compliant with fcntl.\n"
365 );
366
367}