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