diff options
Diffstat (limited to 'src/sh/file.cc')
| -rw-r--r-- | src/sh/file.cc | 367 |
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 | |||
| 26 | const mstring sdot=".",sdots=".."; | ||
| 27 | |||
| 28 | /////////////////////////////////////////////////////////////////// | ||
| 29 | |||
| 30 | inline 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 | |||
| 37 | TOK_IMPL(remfile) { | ||
| 38 | mstring path=DocPath(env,env[0]); | ||
| 39 | if(remove(path.c_str())<0) THROW("htc: Could not remove "<<path); | ||
| 40 | } | ||
| 41 | |||
| 42 | TOK_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 | |||
| 48 | TOK_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 | |||
| 61 | TOK_IMPL(seturi) { | ||
| 62 | Req(env)->uri=env[0]; | ||
| 63 | } | ||
| 64 | |||
| 65 | TOK_IMPL(uri) { | ||
| 66 | out<<Req(env)->uri; | ||
| 67 | } | ||
| 68 | |||
| 69 | TOK_IMPL(pwd) { | ||
| 70 | out<<Req(env)->uri.left_last('/'); | ||
| 71 | } | ||
| 72 | |||
| 73 | TOK_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 | |||
| 84 | TOK_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 | |||
| 92 | TOK_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 | |||
| 98 | TOK_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 | |||
| 104 | TOK_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 | |||
| 114 | TOK_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 | |||
| 122 | static 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 | |||
| 128 | TOK_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 | |||
| 138 | TOK_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 | |||
| 144 | TOK_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 | |||
| 150 | TOK_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 | |||
| 158 | TOK_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 | |||
| 174 | TOK_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 | |||
| 180 | TOK_IMPL(dirmtime) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_mtime; } | ||
| 181 | TOK_IMPL(diruid) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_uid; } | ||
| 182 | TOK_IMPL(dirgid) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_gid; } | ||
| 183 | TOK_IMPL(filesize) { struct stat fs; stat(fs,env,env[0]); out<<fs.st_size; } | ||
| 184 | |||
| 185 | TOK_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 | |||
| 193 | void 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 | } | ||
