summaryrefslogtreecommitdiffabout
path: root/lib/sitecing_util.cc
Side-by-side diff
Diffstat (limited to 'lib/sitecing_util.cc') (more/less context) (show whitespace changes)
-rw-r--r--lib/sitecing_util.cc4
1 files changed, 2 insertions, 2 deletions
diff --git a/lib/sitecing_util.cc b/lib/sitecing_util.cc
index 5466b28..f892a60 100644
--- a/lib/sitecing_util.cc
+++ b/lib/sitecing_util.cc
@@ -1,257 +1,257 @@
#ifdef USE_PCH
#include "pch.h"
#else
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <iostream>
#include <fstream>
#include <cassert>
#include "sitecing/sitecing_util.h"
#endif
namespace sitecing {
/*
* XXX: all of these utilities could be sheerly optimized.
*/
string normalize_path(const string& path,int opts) {
const char *s = path.c_str();
string rv;
string::size_type notslash = 0;
if( (*s)=='.' && s[1]=='/' )
s+=2;
if(opts&strip_leading_slash)
for(;(*s) && (*s)=='/';s++);
for(;*s;s++) {
if( (*s)=='/' ) {
if(s[1]=='/')
continue;
if(s[1]=='.' && s[2]=='/') {
s+=2;
continue;
}
}
if(opts&restrict_dotdot) {
if(
( rv.empty() && s[0]=='.' && s[1]=='.' && s[2]=='/' ) // "^../"
|| ( s[0]=='/' && s[1]=='.' && s[2]=='.' && (s[3]==0 || s[3]=='/') ) // "/..(/|$)"
)
throw utility_restricted_sequence(CODEPOINT,"restricted updir sequence encountered");
}
rv += *s;
if( (*s) != '/' )
notslash=rv.length();
}
if(!(opts&strip_trailing_slash))
notslash++;
if(notslash<rv.length())
rv.erase(notslash); // XXX: check the logic of stripping/not strippling trailing slash
return rv;
}
string strip_prefix(const string& str,const string& prefix) {
- if(str.compare(0,prefix.length(),prefix))
+ if( (str.length()<prefix.length()) || str.compare(0,prefix.length(),prefix))
throw utility_no_prefix(CODEPOINT,"no such prefix");
return str.substr(prefix.length());
}
string strip_suffix(const string& str,const string& suffix) {
- if(str.compare(str.length()-suffix.length(),suffix.length(),suffix))
+ if( (str.length()<suffix.length()) || str.compare(str.length()-suffix.length(),suffix.length(),suffix))
throw utility_no_suffix(CODEPOINT,"no such suffix");
return str.substr(0,str.length()-suffix.length());
}
string dir_name(const string& filename) {
string::size_type sl = filename.find_last_of('/');
if(sl==string::npos)
return ""; // no slashes -- no dir.
string::size_type nosl = filename.find_last_not_of('/',sl);
if(nosl==string::npos)
return ""; // only slashes -- no dir. XXX: only slashes after the last slash... does it mean no dir?
return filename.substr(0,nosl+1);
}
void make_path(const string& path,mode_t mode) {
struct stat st;
for(string::size_type sl=0;sl!=string::npos;sl=path.find('/',sl+1)) {
if(!sl)
continue;
string p = path.substr(0,sl);
if(stat(p.c_str(),&st) || !S_ISDIR(st.st_mode)) {
if(mkdir(p.c_str(),mode))
throw konforka::exception(CODEPOINT,"failed to mkdir()");
}
}
if(stat(path.c_str(),&st) || !S_ISDIR(st.st_mode)) {
if(mkdir(path.c_str(),mode))
throw konforka::exception(CODEPOINT,"failed to mkdir()");
}
}
void file_lock::lock(const string& f) {
unlock();
fd = open(f.c_str(),O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);
if(fd<0)
throw konforka::exception(CODEPOINT,"failed to open/create lockfile");
try {
lock();
}catch(konforka::exception& ke) {
ke.see(CODEPOINT);
close(fd); fd=-1;
throw;
}catch(...) {
close(fd); fd=-1;
throw;
}
}
void file_lock::lock() {
assert(fd>=0);
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence=SEEK_SET;
fl.l_start=fl.l_len=0;
for(int tries=3;tries;tries--) {
if(!fcntl(fd,F_SETLK,&fl))
return;
sleep(8);
}
throw konforka::exception(CODEPOINT,"failed to obtain file lock");
}
void file_lock::unlock() {
if(fd<0)
return;
struct flock fl;
fl.l_type = F_UNLCK;
fl.l_whence=SEEK_SET;
fl.l_start=fl.l_len=0;
int rv = fcntl(fd,F_SETLK,&fl);
close(fd);
fd=-1;
if(rv)
throw konforka::exception(CODEPOINT,"failed to release file lock");
}
void pid_file::set(const string& f,bool u) {
ofstream of(f.c_str(),ios::trunc);
if(!of)
throw konforka::exception(CODEPOINT,"failed to open file for writing pid");
of << getpid() << endl;
of.close();
file_name = f;
unlink_pid = u;
}
void pid_file::unlink() {
if(!unlink_pid)
return;
::unlink(file_name.c_str());
}
void semaphore::init() {
deinit();
semid = semget(IPC_PRIVATE,1,IPC_CREAT|0600);
if(semid<0)
throw konforka::exception(CODEPOINT,"failed to semget()");
if(semctl(semid,0,SETVAL,1))
throw konforka::exception(CODEPOINT,"failed to semctl()");
}
void semaphore::deinit() {
if(semid<0)
return;
semctl(semid,0,IPC_RMID,0);
}
void semaphore::on() {
assert(semid>=0);
struct sembuf sb;
sb.sem_num=0;
sb.sem_op=-1;
sb.sem_flg = SEM_UNDO;
while(semop(semid,&sb,1)<0) {
if(errno!=EINTR)
throw konforka::exception(CODEPOINT,"failed to semop()");
}
}
void semaphore::off() {
assert(semid>=0);
struct sembuf sb;
sb.sem_num=0;
sb.sem_op=1;
sb.sem_flg = SEM_UNDO;
while(semop(semid,&sb,1)<0) {
if(errno!=EINTR)
throw konforka::exception(CODEPOINT,"failed to semop()");
}
}
void semaphore_lock::lock() {
assert(sem);
if(locked)
return;
sem->on();
locked = true;
}
void semaphore_lock::unlock() {
if(!sem)
return;
if(!locked)
return;
sem->off();
locked=false;
}
string combine_path(const string& origin,const string& relative,int opts) {
string r = normalize_path(relative,0);
string rv;
// XXX: what to do if relative is empty is a question, really.
if(r.empty()) {
return normalize_path( (opts&origin_is_file)?dir_name(origin):origin ,strip_leading_slash|restrict_dotdot|strip_trailing_slash);
}else{
if(r[0]=='/') {
r.erase(0,1);
}else{
rv = normalize_path((opts&origin_is_file)?dir_name(origin):origin,restrict_dotdot|strip_trailing_slash);
}
}
string::size_type lsl = rv.rfind('/');
for(string::size_type sl=r.find('/');sl!=string::npos;sl=r.find('/')) {
assert(sl!=0);
if(sl==1 && r[0]=='.') {
// it's a "./"
r.erase(0,2);
}else if(sl==2 && r[0]=='.' && r[1]=='.') {
// we have a "../"
if(lsl==string::npos) {
if(rv.empty() && (opts&fail_beyond_root))
throw utility_beyond_root(CODEPOINT,"went beyond root while combining path");
rv.clear();
}else{
rv.erase(lsl);
lsl = rv.rfind('/');
}
r.erase(0,3);
}else{
// we have a "something/"
lsl = rv.length();
rv += '/';
rv += r.substr(0,sl);
r.erase(0,sl+1);
}
}
if(r.empty())
return rv+'/';
if(r.length()==2 && r[0]=='.' && r[0]=='.') {
if(lsl==string::npos) {
if(rv.empty() & (opts&fail_beyond_root))
throw utility_beyond_root(CODEPOINT,"went beyond root while combining path");
return "/";
}else{
rv.erase(lsl+1);
return rv;
}
}
rv += '/';