summaryrefslogtreecommitdiffabout
path: root/lib/sitecing_util.cc
Unidiff
Diffstat (limited to 'lib/sitecing_util.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--lib/sitecing_util.cc117
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 @@
1#ifdef USE_PCH 1#ifdef USE_PCH
2 #include "pch.h" 2 #include "pch.h"
3#else 3#else
4 #include <sys/stat.h> 4 #include <sys/stat.h>
5 #include <sys/types.h> 5 #include <sys/types.h>
6 #include <unistd.h> 6 #include <unistd.h>
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <sys/ipc.h> 8 #include <sys/ipc.h>
9 #include <sys/sem.h> 9 #include <sys/sem.h>
10 #include <errno.h> 10 #include <errno.h>
11 #include <iostream> 11 #include <iostream>
12 #include <fstream> 12 #include <fstream>
13 #include <cassert> 13 #include <cassert>
14 #include "sitecing/sitecing_util.h" 14 #include "sitecing/sitecing_util.h"
15#endif 15#endif
16 16
17namespace sitecing { 17namespace sitecing {
18 18
19 /* 19 /*
20 * XXX: all of these utilities could be sheerly optimized. 20 * XXX: all of these utilities could be sheerly optimized.
21 */ 21 */
22 22
23 string normalize_path(const string& path,int opts) {
24 const char *s = path.c_str();
25 string rv;
26 string::size_type notslash = 0;
27 if( (*s)=='.' && s[1]=='/' )
28 s+=2;
29 if(opts&strip_leading_slash)
30 for(;(*s) && (*s)=='/';s++);
31 for(;*s;s++) {
32 if( (*s)=='/' ) {
33 if(s[1]=='/')
34 continue;
35 if(s[1]=='.' && s[2]=='/') {
36 s+=2;
37 continue;
38 }
39 }
40 if(opts&restrict_dotdot) {
41 if(
42 ( rv.empty() && s[0]=='.' && s[1]=='.' && s[2]=='/' )// "^../"
43 || ( s[0]=='/' && s[1]=='.' && s[2]=='.' && (s[3]==0 || s[3]=='/') ) // "/..(/|$)"
44 )
45 throw utility_restricted_sequence(CODEPOINT,"restricted updir sequence encountered");
46 }
47 rv += *s;
48 if( (*s) != '/' )
49 notslash=rv.length();
50 }
51 if(!(opts&strip_trailing_slash))
52 notslash++;
53 if(notslash<rv.length())
54 rv.erase(notslash); // XXX: check the logic of stripping/not strippling trailing slash
55 return rv;
56 }
57
58 string strip_prefix(const string& str,const string& prefix) { 23 string strip_prefix(const string& str,const string& prefix) {
59 if( (str.length()<prefix.length()) || str.compare(0,prefix.length(),prefix)) 24 if( (str.length()<prefix.length()) || str.compare(0,prefix.length(),prefix))
60 throw utility_no_prefix(CODEPOINT,"no such prefix"); 25 throw utility_no_prefix(CODEPOINT,"no such prefix");
61 return str.substr(prefix.length()); 26 return str.substr(prefix.length());
62 } 27 }
63 28
64 string strip_suffix(const string& str,const string& suffix) { 29 string strip_suffix(const string& str,const string& suffix) {
65 if( (str.length()<suffix.length()) || str.compare(str.length()-suffix.length(),suffix.length(),suffix)) 30 if( (str.length()<suffix.length()) || str.compare(str.length()-suffix.length(),suffix.length(),suffix))
66 throw utility_no_suffix(CODEPOINT,"no such suffix"); 31 throw utility_no_suffix(CODEPOINT,"no such suffix");
67 return str.substr(0,str.length()-suffix.length()); 32 return str.substr(0,str.length()-suffix.length());
68 } 33 }
69 34
70 string dir_name(const string& filename) {
71 string::size_type sl = filename.find_last_of('/');
72 if(sl==string::npos)
73 return ""; // no slashes -- no dir.
74 string::size_type nosl = filename.find_last_not_of('/',sl);
75 if(nosl==string::npos)
76 return ""; // only slashes -- no dir. XXX: only slashes after the last slash... does it mean no dir?
77 return filename.substr(0,nosl+1);
78 }
79
80 void make_path(const string& path,mode_t mode) {
81 struct stat st;
82 for(string::size_type sl=0;sl!=string::npos;sl=path.find('/',sl+1)) {
83 if(!sl)
84 continue;
85 string p = path.substr(0,sl);
86 if(stat(p.c_str(),&st) || !S_ISDIR(st.st_mode)) {
87 if(mkdir(p.c_str(),mode))
88 throw konforka::exception(CODEPOINT,"failed to mkdir()");
89 }
90 }
91 if(stat(path.c_str(),&st) || !S_ISDIR(st.st_mode)) {
92 if(mkdir(path.c_str(),mode))
93 throw konforka::exception(CODEPOINT,"failed to mkdir()");
94 }
95 }
96
97 void file_lock::lock(const string& f) { 35 void file_lock::lock(const string& f) {
98 unlock(); 36 unlock();
99 fd = open(f.c_str(),O_CREAT|O_RDWR,S_IRUSR|S_IWUSR); 37 fd = open(f.c_str(),O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);
100 if(fd<0) 38 if(fd<0)
101 throw konforka::exception(CODEPOINT,"failed to open/create lockfile"); 39 throw konforka::exception(CODEPOINT,"failed to open/create lockfile");
102 try { 40 try {
103 lock(); 41 lock();
104 }catch(konforka::exception& ke) { 42 }catch(konforka::exception& ke) {
105 ke.see(CODEPOINT); 43 ke.see(CODEPOINT);
106 close(fd); fd=-1; 44 close(fd); fd=-1;
107 throw; 45 throw;
108 }catch(...) { 46 }catch(...) {
109 close(fd); fd=-1; 47 close(fd); fd=-1;
110 throw; 48 throw;
111 } 49 }
112 } 50 }
113 void file_lock::lock() { 51 void file_lock::lock() {
114 assert(fd>=0); 52 assert(fd>=0);
115 struct flock fl; 53 struct flock fl;
116 fl.l_type = F_WRLCK; 54 fl.l_type = F_WRLCK;
117 fl.l_whence=SEEK_SET; 55 fl.l_whence=SEEK_SET;
118 fl.l_start=fl.l_len=0; 56 fl.l_start=fl.l_len=0;
119 for(int tries=3;tries;tries--) { 57 for(int tries=3;tries;tries--) {
120 if(!fcntl(fd,F_SETLK,&fl)) 58 if(!fcntl(fd,F_SETLK,&fl))
121 return; 59 return;
122 sleep(8); 60 sleep(8);
123 } 61 }
124 throw konforka::exception(CODEPOINT,"failed to obtain file lock"); 62 throw konforka::exception(CODEPOINT,"failed to obtain file lock");
125 } 63 }
126 void file_lock::unlock() { 64 void file_lock::unlock() {
127 if(fd<0) 65 if(fd<0)
128 return; 66 return;
129 struct flock fl; 67 struct flock fl;
130 fl.l_type = F_UNLCK; 68 fl.l_type = F_UNLCK;
131 fl.l_whence=SEEK_SET; 69 fl.l_whence=SEEK_SET;
132 fl.l_start=fl.l_len=0; 70 fl.l_start=fl.l_len=0;
133 int rv = fcntl(fd,F_SETLK,&fl); 71 int rv = fcntl(fd,F_SETLK,&fl);
134 close(fd); 72 close(fd);
135 fd=-1; 73 fd=-1;
136 if(rv) 74 if(rv)
137 throw konforka::exception(CODEPOINT,"failed to release file lock"); 75 throw konforka::exception(CODEPOINT,"failed to release file lock");
138 } 76 }
139 77
140 void pid_file::set(const string& f,bool u) { 78 void pid_file::set(const string& f,bool u) {
141 ofstream of(f.c_str(),ios::trunc); 79 ofstream of(f.c_str(),ios::trunc);
142 if(!of) 80 if(!of)
143 throw konforka::exception(CODEPOINT,"failed to open file for writing pid"); 81 throw konforka::exception(CODEPOINT,"failed to open file for writing pid");
144 of << getpid() << endl; 82 of << getpid() << endl;
145 of.close(); 83 of.close();
146 file_name = f; 84 file_name = f;
147 unlink_pid = u; 85 unlink_pid = u;
148 } 86 }
149 void pid_file::unlink() { 87 void pid_file::unlink() {
150 if(!unlink_pid) 88 if(!unlink_pid)
151 return; 89 return;
152 ::unlink(file_name.c_str()); 90 ::unlink(file_name.c_str());
153 } 91 }
154 92
155 void semaphore::init() { 93 void semaphore::init() {
156 deinit(); 94 deinit();
157 semid = semget(IPC_PRIVATE,1,IPC_CREAT|0600); 95 semid = semget(IPC_PRIVATE,1,IPC_CREAT|0600);
158 if(semid<0) 96 if(semid<0)
159 throw konforka::exception(CODEPOINT,"failed to semget()"); 97 throw konforka::exception(CODEPOINT,"failed to semget()");
160 if(semctl(semid,0,SETVAL,1)) 98 if(semctl(semid,0,SETVAL,1))
161 throw konforka::exception(CODEPOINT,"failed to semctl()"); 99 throw konforka::exception(CODEPOINT,"failed to semctl()");
162 } 100 }
163 void semaphore::deinit() { 101 void semaphore::deinit() {
164 if(semid<0) 102 if(semid<0)
165 return; 103 return;
166 semctl(semid,0,IPC_RMID,0); 104 semctl(semid,0,IPC_RMID,0);
167 } 105 }
168 void semaphore::on() { 106 void semaphore::on() {
169 assert(semid>=0); 107 assert(semid>=0);
170 struct sembuf sb; 108 struct sembuf sb;
171 sb.sem_num=0; 109 sb.sem_num=0;
172 sb.sem_op=-1; 110 sb.sem_op=-1;
173 sb.sem_flg = SEM_UNDO; 111 sb.sem_flg = SEM_UNDO;
174 while(semop(semid,&sb,1)<0) { 112 while(semop(semid,&sb,1)<0) {
175 if(errno!=EINTR) 113 if(errno!=EINTR)
176 throw konforka::exception(CODEPOINT,"failed to semop()"); 114 throw konforka::exception(CODEPOINT,"failed to semop()");
177 } 115 }
178 } 116 }
179 void semaphore::off() { 117 void semaphore::off() {
180 assert(semid>=0); 118 assert(semid>=0);
181 struct sembuf sb; 119 struct sembuf sb;
182 sb.sem_num=0; 120 sb.sem_num=0;
183 sb.sem_op=1; 121 sb.sem_op=1;
184 sb.sem_flg = SEM_UNDO; 122 sb.sem_flg = SEM_UNDO;
185 while(semop(semid,&sb,1)<0) { 123 while(semop(semid,&sb,1)<0) {
186 if(errno!=EINTR) 124 if(errno!=EINTR)
187 throw konforka::exception(CODEPOINT,"failed to semop()"); 125 throw konforka::exception(CODEPOINT,"failed to semop()");
188 } 126 }
189 } 127 }
190 128
191 void semaphore_lock::lock() { 129 void semaphore_lock::lock() {
192 assert(sem); 130 assert(sem);
193 if(locked) 131 if(locked)
194 return; 132 return;
195 sem->on(); 133 sem->on();
196 locked = true; 134 locked = true;
197 } 135 }
198 void semaphore_lock::unlock() { 136 void semaphore_lock::unlock() {
199 if(!sem) 137 if(!sem)
200 return; 138 return;
201 if(!locked) 139 if(!locked)
202 return; 140 return;
203 sem->off(); 141 sem->off();
204 locked=false; 142 locked=false;
205 } 143 }
206 144
207 string combine_path(const string& origin,const string& relative,int opts) {
208 string r = normalize_path(relative,0);
209 string rv;
210 // XXX: what to do if relative is empty is a question, really.
211 if(r.empty()) {
212 return normalize_path( (opts&origin_is_file)?dir_name(origin):origin ,strip_leading_slash|restrict_dotdot|strip_trailing_slash);
213 }else{
214 if(r[0]=='/') {
215 r.erase(0,1);
216 }else{
217 rv = normalize_path((opts&origin_is_file)?dir_name(origin):origin,restrict_dotdot|strip_trailing_slash);
218 }
219 }
220 string::size_type lsl = rv.rfind('/');
221 for(string::size_type sl=r.find('/');sl!=string::npos;sl=r.find('/')) {
222 assert(sl!=0);
223 if(sl==1 && r[0]=='.') {
224 // it's a "./"
225 r.erase(0,2);
226 }else if(sl==2 && r[0]=='.' && r[1]=='.') {
227 // we have a "../"
228 if(lsl==string::npos) {
229 if(rv.empty() && (opts&fail_beyond_root))
230 throw utility_beyond_root(CODEPOINT,"went beyond root while combining path");
231 rv.clear();
232 }else{
233 rv.erase(lsl);
234 lsl = rv.rfind('/');
235 }
236 r.erase(0,3);
237 }else{
238 // we have a "something/"
239 lsl = rv.length();
240 rv += '/';
241 rv += r.substr(0,sl);
242 r.erase(0,sl+1);
243 }
244 }
245 if(r.empty())
246 return rv+'/';
247 if(r.length()==2 && r[0]=='.' && r[0]=='.') {
248 if(lsl==string::npos) {
249 if(rv.empty() & (opts&fail_beyond_root))
250 throw utility_beyond_root(CODEPOINT,"went beyond root while combining path");
251 return "/";
252 }else{
253 rv.erase(lsl+1);
254 return rv;
255 }
256 }
257 rv += '/';
258 rv += r;
259 return rv;
260 }
261
262 void auto_chdir::pushdir(const string& td,bool ap) { 145 void auto_chdir::pushdir(const string& td,bool ap) {
263 /* TODO: make use of fchdir(2) instead */ 146 /* TODO: make use of fchdir(2) instead */
264 char *tmp = getcwd(0,0); 147 char *tmp = getcwd(0,0);
265 assert(tmp); 148 assert(tmp);
266 saved_pwd = tmp; 149 saved_pwd = tmp;
267 free(tmp); 150 free(tmp);
268 autopop=ap; 151 autopop=ap;
269 if(chdir(td.c_str())) 152 if(chdir(td.c_str()))
270 throw konforka::exception(CODEPOINT,"failed to chdir()"); 153 throw konforka::exception(CODEPOINT,"failed to chdir()");
271 } 154 }
272 void auto_chdir::popdir() { 155 void auto_chdir::popdir() {
273 autopop=false; 156 autopop=false;
274 if(chdir(saved_pwd.c_str())) 157 if(chdir(saved_pwd.c_str()))
275 throw konforka::exception(CODEPOINT,"failed to chdir()"); 158 throw konforka::exception(CODEPOINT,"failed to chdir()");
276 // XXX: or should it be thrown? after all we call it from destructor... 159 // XXX: or should it be thrown? after all we call it from destructor...
277 } 160 }
278 161
279} 162}