-rw-r--r-- | lib/sitecing_util.cc | 117 |
1 files changed, 0 insertions, 117 deletions
diff --git a/lib/sitecing_util.cc b/lib/sitecing_util.cc index f892a60..f1432df 100644 --- a/lib/sitecing_util.cc +++ b/lib/sitecing_util.cc @@ -1,279 +1,162 @@ #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.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.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 += '/'; - rv += r; - return rv; - } - void auto_chdir::pushdir(const string& td,bool ap) { /* TODO: make use of fchdir(2) instead */ char *tmp = getcwd(0,0); assert(tmp); saved_pwd = tmp; free(tmp); autopop=ap; if(chdir(td.c_str())) throw konforka::exception(CODEPOINT,"failed to chdir()"); } void auto_chdir::popdir() { autopop=false; if(chdir(saved_pwd.c_str())) throw konforka::exception(CODEPOINT,"failed to chdir()"); // XXX: or should it be thrown? after all we call it from destructor... } } |