]>
Commit | Line | Data |
---|---|---|
a09a7e79 | 1 | /* |
b9b0fd4c | 2 | * Copyright (C) 2004-2011 See the AUTHORS file for details. |
a09a7e79 | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License version 2 as published | |
6 | * by the Free Software Foundation. | |
7 | */ | |
6dcacaa7 | 8 | |
b58cb3c8 | 9 | #include "FileUtils.h" |
1761fe71 | 10 | #include "ExecSock.h" |
73d8456d | 11 | #include "Utils.h" |
1761fe71 US |
12 | #include "ZNCDebug.h" |
13 | #include <errno.h> | |
14 | #include <fcntl.h> | |
15 | #include <pwd.h> | |
e72c4456 | 16 | #include <sys/stat.h> |
17 | #include <sys/types.h> | |
d456374e | 18 | #include <sys/wait.h> |
ecf431f2 | 19 | |
accb2e46 | 20 | #ifndef HAVE_LSTAT |
21 | # define lstat(a, b) stat(a, b) | |
22 | #endif | |
23 | ||
e6ede6de | 24 | #ifndef O_BINARY |
25 | # define O_BINARY 0 | |
26 | #endif | |
27 | ||
f9ffe6f4 US |
28 | CString CFile::m_sHomePath; |
29 | ||
ecf431f2 | 30 | CFile::CFile() { |
a4ca68f6 | 31 | m_iFD = -1; |
70358cab | 32 | ResetError(); |
ecf431f2 | 33 | } |
b58cb3c8 | 34 | |
beb5b49b | 35 | CFile::CFile(const CString& sLongName) { |
a4ca68f6 | 36 | m_iFD = -1; |
37 | ||
70358cab | 38 | ResetError(); |
9db44ab1 | 39 | SetFileName(sLongName); |
40 | } | |
41 | ||
42 | CFile::~CFile() { | |
70b60aa4 | 43 | Close(); |
9db44ab1 | 44 | } |
45 | ||
46 | void CFile::SetFileName(const CString& sLongName) { | |
cb2e50a5 | 47 | if (sLongName.Left(2) == "~/") { |
f9ffe6f4 | 48 | m_sLongName = CFile::GetHomePath() + sLongName.substr(1); |
cb2e50a5 US |
49 | } else |
50 | m_sLongName = sLongName; | |
b58cb3c8 | 51 | |
52 | m_sShortName = sLongName; | |
653fe468 | 53 | m_sShortName.TrimRight("/"); |
b58cb3c8 | 54 | |
beb5b49b | 55 | CString::size_type uPos = m_sShortName.rfind('/'); |
56 | if (uPos != CString::npos) { | |
b58cb3c8 | 57 | m_sShortName = m_sShortName.substr(uPos +1); |
58 | } | |
59 | } | |
60 | ||
f7825e00 | 61 | bool CFile::IsDir(const CString& sLongName, bool bUseLstat) { |
ada9b8cf | 62 | if (sLongName.Equals("/")) |
63 | return CFile::FType(sLongName, FT_DIRECTORY, bUseLstat); | |
64 | ||
f7825e00 | 65 | // Some OS don't like trailing slashes for directories |
9a8fbdb6 | 66 | return CFile::FType(sLongName.TrimRight_n("/"), |
f7825e00 | 67 | FT_DIRECTORY, bUseLstat); |
68 | } | |
69 | ||
beb5b49b | 70 | bool CFile::IsReg(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_REGULAR, bUseLstat); } |
beb5b49b | 71 | bool CFile::IsChr(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_CHARACTER, bUseLstat); } |
72 | bool CFile::IsBlk(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_BLOCK, bUseLstat); } | |
73 | bool CFile::IsFifo(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_FIFO, bUseLstat); } | |
74 | bool CFile::IsLnk(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_LINK, bUseLstat); } | |
75 | bool CFile::IsSock(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_SOCK, bUseLstat); } | |
b58cb3c8 | 76 | |
81eef389 | 77 | bool CFile::IsReg(bool bUseLstat) const { return CFile::IsReg(m_sLongName, bUseLstat); } |
78 | bool CFile::IsDir(bool bUseLstat) const { return CFile::IsDir(m_sLongName, bUseLstat); } | |
79 | bool CFile::IsChr(bool bUseLstat) const { return CFile::IsChr(m_sLongName, bUseLstat); } | |
80 | bool CFile::IsBlk(bool bUseLstat) const { return CFile::IsBlk(m_sLongName, bUseLstat); } | |
81 | bool CFile::IsFifo(bool bUseLstat) const { return CFile::IsFifo(m_sLongName, bUseLstat); } | |
82 | bool CFile::IsLnk(bool bUseLstat) const { return CFile::IsLnk(m_sLongName, bUseLstat); } | |
83 | bool CFile::IsSock(bool bUseLstat) const { return CFile::IsSock(m_sLongName, bUseLstat); } | |
b58cb3c8 | 84 | |
b58cb3c8 | 85 | // for gettin file types, using fstat instead |
7999cacf | 86 | bool CFile::FType(const CString& sFileName, EFileTypes eType, bool bUseLstat) { |
b58cb3c8 | 87 | struct stat st; |
88 | ||
89 | if (!bUseLstat) { | |
90 | if (stat(sFileName.c_str(), &st) != 0) { | |
91 | return false; | |
92 | } | |
93 | } else { | |
94 | if (lstat(sFileName.c_str(), &st) != 0) { | |
95 | return false; | |
96 | } | |
97 | } | |
98 | ||
99 | switch (eType) { | |
100 | case FT_REGULAR: | |
101 | return S_ISREG(st.st_mode); | |
102 | case FT_DIRECTORY: | |
103 | return S_ISDIR(st.st_mode); | |
104 | case FT_CHARACTER: | |
105 | return S_ISCHR(st.st_mode); | |
106 | case FT_BLOCK: | |
107 | return S_ISBLK(st.st_mode); | |
108 | case FT_FIFO: | |
109 | return S_ISFIFO(st.st_mode); | |
110 | case FT_LINK: | |
111 | return S_ISLNK(st.st_mode); | |
112 | case FT_SOCK: | |
113 | return S_ISSOCK(st.st_mode); | |
114 | default: | |
860ccb7d | 115 | break; |
b58cb3c8 | 116 | } |
117 | return false; | |
118 | } | |
119 | ||
120 | // | |
121 | // Functions to retrieve file information | |
122 | // | |
123 | bool CFile::Exists() const { return CFile::Exists(m_sLongName); } | |
fa285b7c | 124 | off_t CFile::GetSize() const { return CFile::GetSize(m_sLongName); } |
5eed1f43 | 125 | time_t CFile::GetATime() const { return CFile::GetATime(m_sLongName); } |
126 | time_t CFile::GetMTime() const { return CFile::GetMTime(m_sLongName); } | |
127 | time_t CFile::GetCTime() const { return CFile::GetCTime(m_sLongName); } | |
fa285b7c | 128 | uid_t CFile::GetUID() const { return CFile::GetUID(m_sLongName); } |
129 | gid_t CFile::GetGID() const { return CFile::GetGID(m_sLongName); } | |
beb5b49b | 130 | bool CFile::Exists(const CString& sFile) { |
b58cb3c8 | 131 | struct stat st; |
132 | return (stat(sFile.c_str(), &st) == 0); | |
133 | } | |
134 | ||
fa285b7c | 135 | off_t CFile::GetSize(const CString& sFile) { |
b58cb3c8 | 136 | struct stat st; |
c64d7bc1 | 137 | if (stat(sFile.c_str(), &st) != 0) { |
b58cb3c8 | 138 | return 0; |
139 | } | |
140 | ||
141 | return (S_ISREG(st.st_mode)) ? st.st_size : 0; | |
142 | } | |
143 | ||
5eed1f43 | 144 | time_t CFile::GetATime(const CString& sFile) { |
b58cb3c8 | 145 | struct stat st; |
146 | return (stat(sFile.c_str(), &st) != 0) ? 0 : st.st_atime; | |
147 | } | |
148 | ||
5eed1f43 | 149 | time_t CFile::GetMTime(const CString& sFile) { |
b58cb3c8 | 150 | struct stat st; |
151 | return (stat(sFile.c_str(), &st) != 0) ? 0 : st.st_mtime; | |
152 | } | |
153 | ||
5eed1f43 | 154 | time_t CFile::GetCTime(const CString& sFile) { |
b58cb3c8 | 155 | struct stat st; |
156 | return (stat(sFile.c_str(), &st) != 0) ? 0 : st.st_ctime; | |
157 | } | |
158 | ||
fa285b7c | 159 | uid_t CFile::GetUID(const CString& sFile) { |
b58cb3c8 | 160 | struct stat st; |
161 | return (stat(sFile.c_str(), &st) != 0) ? -1 : (int) st.st_uid; | |
162 | } | |
163 | ||
fa285b7c | 164 | gid_t CFile::GetGID(const CString& sFile) { |
b58cb3c8 | 165 | struct stat st; |
166 | return (stat(sFile.c_str(), &st) != 0) ? -1 : (int) st.st_gid; | |
167 | } | |
beb5b49b | 168 | int CFile::GetInfo(const CString& sFile, struct stat& st) { |
b58cb3c8 | 169 | return stat(sFile.c_str(), &st); |
170 | } | |
171 | ||
172 | // | |
173 | // Functions to manipulate the file on the filesystem | |
174 | // | |
70358cab US |
175 | bool CFile::Delete() { |
176 | if (CFile::Delete(m_sLongName)) | |
177 | return true; | |
178 | m_bHadError = true; | |
179 | return false; | |
180 | } | |
181 | ||
fa285b7c | 182 | bool CFile::Move(const CString& sNewFileName, bool bOverwrite) { |
70358cab US |
183 | if (CFile::Move(m_sLongName, sNewFileName, bOverwrite)) |
184 | return true; | |
185 | m_bHadError = true; | |
186 | return false; | |
b58cb3c8 | 187 | } |
188 | ||
fa285b7c | 189 | bool CFile::Copy(const CString& sNewFileName, bool bOverwrite) { |
70358cab US |
190 | if (CFile::Copy(m_sLongName, sNewFileName, bOverwrite)) |
191 | return true; | |
192 | m_bHadError = true; | |
193 | return false; | |
6be9f989 | 194 | } |
195 | ||
beb5b49b | 196 | bool CFile::Delete(const CString& sFileName) { |
b58cb3c8 | 197 | return (unlink(sFileName.c_str()) == 0) ? true : false; |
198 | } | |
199 | ||
beb5b49b | 200 | bool CFile::Move(const CString& sOldFileName, const CString& sNewFileName, bool bOverwrite) { |
c64d7bc1 | 201 | if ((!bOverwrite) && (CFile::Exists(sNewFileName))) { |
8f1027d6 | 202 | errno = EEXIST; |
b58cb3c8 | 203 | return false; |
204 | } | |
205 | ||
20f3ad92 | 206 | return (rename(sOldFileName.c_str(), sNewFileName.c_str()) == 0); |
b58cb3c8 | 207 | } |
208 | ||
6be9f989 | 209 | bool CFile::Copy(const CString& sOldFileName, const CString& sNewFileName, bool bOverwrite) { |
c64d7bc1 | 210 | if ((!bOverwrite) && (CFile::Exists(sNewFileName))) { |
8f1027d6 | 211 | errno = EEXIST; |
6be9f989 | 212 | return false; |
213 | } | |
214 | ||
215 | CFile OldFile(sOldFileName); | |
216 | CFile NewFile(sNewFileName); | |
217 | ||
6345ce12 | 218 | if (!OldFile.Open()) { |
6be9f989 | 219 | return false; |
220 | } | |
221 | ||
222 | if (!NewFile.Open(O_WRONLY | O_CREAT | O_TRUNC)) { | |
223 | return false; | |
224 | } | |
225 | ||
226 | char szBuf[8192]; | |
e6007747 | 227 | int len = 0; |
6be9f989 | 228 | |
6b4b5438 | 229 | while ((len = OldFile.Read(szBuf, 8192))) { |
e6007747 | 230 | if (len < 0) { |
235b10c2 | 231 | DEBUG("CFile::Copy() failed: " << strerror(errno)); |
e6007747 | 232 | OldFile.Close(); |
233 | ||
234 | // That file is only a partial copy, get rid of it | |
235 | NewFile.Close(); | |
236 | NewFile.Delete(); | |
237 | ||
238 | return false; | |
239 | } | |
6be9f989 | 240 | NewFile.Write(szBuf, len); |
241 | } | |
242 | ||
243 | OldFile.Close(); | |
244 | NewFile.Close(); | |
245 | ||
35d3ea42 AS |
246 | struct stat st; |
247 | GetInfo(sOldFileName, st); | |
248 | Chmod(sNewFileName, st.st_mode); | |
249 | ||
6be9f989 | 250 | return true; |
251 | } | |
252 | ||
b58cb3c8 | 253 | bool CFile::Chmod(mode_t mode) { |
69279c51 | 254 | if (m_iFD == -1) { |
8f1027d6 | 255 | errno = EBADF; |
69279c51 | 256 | return false; |
257 | } | |
70358cab US |
258 | if (fchmod(m_iFD, mode) != 0) { |
259 | m_bHadError = true; | |
260 | return false; | |
261 | } | |
262 | return true; | |
b58cb3c8 | 263 | } |
264 | ||
beb5b49b | 265 | bool CFile::Chmod(const CString& sFile, mode_t mode) { |
b58cb3c8 | 266 | return (chmod(sFile.c_str(), mode) == 0); |
267 | } | |
268 | ||
4e767b3e | 269 | bool CFile::Seek(off_t uPos) { |
8f1027d6 US |
270 | /* This sets errno in case m_iFD == -1 */ |
271 | errno = EBADF; | |
272 | ||
4e767b3e | 273 | if (m_iFD != -1 && lseek(m_iFD, uPos, SEEK_SET) == uPos) { |
ecf431f2 | 274 | ClearBuffer(); |
275 | return true; | |
276 | } | |
70358cab US |
277 | m_bHadError = true; |
278 | ||
ecf431f2 | 279 | return false; |
280 | } | |
281 | ||
0a622749 | 282 | bool CFile::Truncate() { |
8f1027d6 US |
283 | /* This sets errno in case m_iFD == -1 */ |
284 | errno = EBADF; | |
285 | ||
0a622749 | 286 | if (m_iFD != -1 && ftruncate(m_iFD, 0) == 0) { |
287 | ClearBuffer(); | |
288 | return true; | |
289 | } | |
290 | ||
70358cab US |
291 | m_bHadError = true; |
292 | ||
0a622749 | 293 | return false; |
294 | } | |
295 | ||
f618ce2a | 296 | bool CFile::Sync() { |
8f1027d6 US |
297 | /* This sets errno in case m_iFD == -1 */ |
298 | errno = EBADF; | |
299 | ||
70358cab US |
300 | if (m_iFD != -1 && fsync(m_iFD) == 0) |
301 | return true; | |
302 | m_bHadError = true; | |
303 | return false; | |
f618ce2a | 304 | } |
305 | ||
ecf431f2 | 306 | bool CFile::Open(const CString& sFileName, int iFlags, mode_t iMode) { |
307 | SetFileName(sFileName); | |
308 | return Open(iFlags, iMode); | |
b58cb3c8 | 309 | } |
310 | ||
311 | bool CFile::Open(int iFlags, mode_t iMode) { | |
312 | if (m_iFD != -1) { | |
8f1027d6 | 313 | errno = EEXIST; |
70358cab | 314 | m_bHadError = true; |
b58cb3c8 | 315 | return false; |
316 | } | |
317 | ||
36505a8d | 318 | // We never want to get a controlling TTY through this -> O_NOCTTY |
e6ede6de | 319 | iMode |= O_NOCTTY; |
320 | ||
321 | // Some weird OS from MS needs O_BINARY or else it generates fake EOFs | |
322 | // when reading ^Z from a file. | |
323 | iMode |= O_BINARY; | |
324 | ||
325 | m_iFD = open(m_sLongName.c_str(), iFlags, iMode); | |
70358cab US |
326 | if (m_iFD < 0) { |
327 | m_bHadError = true; | |
0a622749 | 328 | return false; |
70358cab | 329 | } |
0a622749 | 330 | |
73d8456d | 331 | /* Make sure this FD isn't given to childs */ |
332 | SetFdCloseOnExec(m_iFD); | |
333 | ||
0a622749 | 334 | return true; |
b58cb3c8 | 335 | } |
336 | ||
337 | int CFile::Read(char *pszBuffer, int iBytes) { | |
338 | if (m_iFD == -1) { | |
8f1027d6 | 339 | errno = EBADF; |
b58cb3c8 | 340 | return -1; |
341 | } | |
342 | ||
70358cab US |
343 | int res = read(m_iFD, pszBuffer, iBytes); |
344 | if (res != iBytes) | |
345 | m_bHadError = true; | |
346 | return res; | |
b58cb3c8 | 347 | } |
348 | ||
c2b8b7c6 | 349 | bool CFile::ReadLine(CString& sData, const CString & sDelimiter) { |
751f267f | 350 | char buff[4096]; |
4f6d72fe | 351 | int iBytes; |
ecf431f2 | 352 | |
b58cb3c8 | 353 | if (m_iFD == -1) { |
8f1027d6 | 354 | errno = EBADF; |
b58cb3c8 | 355 | return false; |
356 | } | |
357 | ||
4f6d72fe | 358 | do { |
c2b8b7c6 | 359 | CString::size_type iFind = m_sBuffer.find(sDelimiter); |
beb5b49b | 360 | if (iFind != CString::npos) { |
751f267f | 361 | // We found a line, return it |
90859a3f | 362 | sData = m_sBuffer.substr(0, iFind + sDelimiter.length()); |
363 | m_sBuffer.erase(0, iFind + sDelimiter.length()); | |
751f267f | 364 | return true; |
b58cb3c8 | 365 | } |
366 | ||
4f6d72fe | 367 | iBytes = read(m_iFD, buff, sizeof(buff)); |
368 | ||
369 | if (iBytes > 0) { | |
370 | m_sBuffer.append(buff, iBytes); | |
b58cb3c8 | 371 | } |
4f6d72fe | 372 | } while (iBytes > 0); |
b58cb3c8 | 373 | |
751f267f | 374 | // We are at the end of the file or an error happened |
b58cb3c8 | 375 | |
90859a3f | 376 | if (!m_sBuffer.empty()) { |
751f267f | 377 | // ..but there is still some partial line in the buffer |
c2b8b7c6 | 378 | sData = m_sBuffer; |
379 | m_sBuffer.clear(); | |
e522c7f2 | 380 | return true; |
c2b8b7c6 | 381 | } |
382 | ||
751f267f | 383 | // Nothing left for reading :( |
384 | return false; | |
b58cb3c8 | 385 | } |
386 | ||
b7f38c4d | 387 | bool CFile::ReadFile(CString& sData, size_t iMaxSize) { |
388 | char buff[4096]; | |
389 | size_t iBytesRead = 0; | |
390 | ||
391 | sData.clear(); | |
392 | ||
393 | while (iBytesRead < iMaxSize) { | |
394 | int iBytes = Read(buff, sizeof(buff)); | |
395 | ||
396 | if (iBytes < 0) | |
397 | // Error | |
398 | return false; | |
399 | ||
400 | if (iBytes == 0) | |
401 | // EOF | |
402 | return true; | |
403 | ||
404 | sData.append(buff, iBytes); | |
b17bfe79 | 405 | iBytesRead += iBytes; |
b7f38c4d | 406 | } |
407 | ||
408 | // Buffer limit reached | |
409 | return false; | |
410 | } | |
411 | ||
b58cb3c8 | 412 | int CFile::Write(const char *pszBuffer, u_int iBytes) { |
413 | if (m_iFD == -1) { | |
8f1027d6 | 414 | errno = EBADF; |
b58cb3c8 | 415 | return -1; |
416 | } | |
417 | ||
70358cab US |
418 | u_int res = write(m_iFD, pszBuffer, iBytes); |
419 | if (res != iBytes) | |
420 | m_bHadError = true; | |
421 | return res; | |
b58cb3c8 | 422 | } |
423 | ||
beb5b49b | 424 | int CFile::Write(const CString & sData) { |
b58cb3c8 | 425 | return Write(sData.data(), sData.size()); |
426 | } | |
a4ca68f6 | 427 | void CFile::Close() { |
70b60aa4 | 428 | if (m_iFD >= 0) { |
22b219db | 429 | if (close(m_iFD) < 0) { |
70358cab | 430 | m_bHadError = true; |
22b219db | 431 | DEBUG("CFile::Close(): close() failed with [" |
432 | << strerror(errno) << "]"); | |
433 | } | |
a4ca68f6 | 434 | } |
70b60aa4 | 435 | m_iFD = -1; |
436 | ClearBuffer(); | |
a4ca68f6 | 437 | } |
ecf431f2 | 438 | void CFile::ClearBuffer() { m_sBuffer.clear(); } |
b58cb3c8 | 439 | |
12734782 | 440 | bool CFile::TryExLock(const CString& sLockFile, int iFlags) { |
441 | Open(sLockFile, iFlags); | |
442 | return TryExLock(); | |
443 | } | |
444 | ||
445 | bool CFile::TryExLock() { | |
33ce80f4 | 446 | return Lock(F_WRLCK, false); |
447 | } | |
448 | ||
449 | bool CFile::ExLock() { | |
450 | return Lock(F_WRLCK, true); | |
12734782 | 451 | } |
452 | ||
453 | bool CFile::UnLock() { | |
33ce80f4 | 454 | return Lock(F_UNLCK, true); |
12734782 | 455 | } |
456 | ||
33ce80f4 | 457 | bool CFile::Lock(int iType, bool bBlocking) { |
458 | struct flock fl; | |
459 | ||
12734782 | 460 | if (m_iFD == -1) { |
461 | return false; | |
462 | } | |
463 | ||
33ce80f4 | 464 | fl.l_type = iType; |
465 | fl.l_whence = SEEK_SET; | |
466 | fl.l_start = 0; | |
467 | fl.l_len = 0; | |
d735e9d8 | 468 | return (fcntl(m_iFD, (bBlocking ? F_SETLKW : F_SETLK), &fl) != -1); |
12734782 | 469 | } |
470 | ||
ecf431f2 | 471 | bool CFile::IsOpen() const { return (m_iFD != -1); } |
beb5b49b | 472 | CString CFile::GetLongName() const { return m_sLongName; } |
473 | CString CFile::GetShortName() const { return m_sShortName; } | |
ecf431f2 | 474 | CString CFile::GetDir() const { |
475 | CString sDir(m_sLongName); | |
476 | ||
477 | while (!sDir.empty() && sDir.Right(1) != "/" && sDir.Right(1) != "\\") { | |
478 | sDir.RightChomp(); | |
479 | } | |
480 | ||
481 | return sDir; | |
482 | } | |
483 | ||
f9ffe6f4 US |
484 | void CFile::InitHomePath(const CString& sFallback) { |
485 | const char *home = getenv("HOME"); | |
486 | ||
487 | m_sHomePath.clear(); | |
488 | if (home) { | |
489 | m_sHomePath = home; | |
490 | } | |
491 | ||
492 | if (m_sHomePath.empty()) { | |
493 | const struct passwd* pUserInfo = getpwuid(getuid()); | |
494 | ||
495 | if (pUserInfo) { | |
496 | m_sHomePath = pUserInfo->pw_dir; | |
497 | } | |
498 | } | |
499 | ||
500 | if (m_sHomePath.empty()) { | |
501 | m_sHomePath = sFallback; | |
502 | } | |
503 | } | |
504 | ||
00613bc9 | 505 | CString CDir::ChangeDir(const CString& sPath, const CString& sAdd, const CString& sHome) { |
506 | CString sHomeDir(sHome); | |
507 | ||
508 | if (sHomeDir.empty()) { | |
f9ffe6f4 | 509 | sHomeDir = CFile::GetHomePath(); |
00613bc9 | 510 | } |
511 | ||
01bc68b1 | 512 | if (sAdd == "~") { |
513 | return sHomeDir; | |
514 | } | |
515 | ||
00613bc9 | 516 | CString sAddDir(sAdd); |
01bc68b1 | 517 | |
518 | if (sAddDir.Left(2) == "~/") { | |
519 | sAddDir.LeftChomp(); | |
520 | sAddDir = sHomeDir + sAddDir; | |
521 | } | |
522 | ||
523 | CString sRet = ((sAddDir.size()) && (sAddDir[0] == '/')) ? "" : sPath; | |
524 | sAddDir += "/"; | |
525 | CString sCurDir; | |
526 | ||
527 | if (sRet.Right(1) == "/") { | |
528 | sRet.RightChomp(); | |
529 | } | |
530 | ||
531 | for (unsigned int a = 0; a < sAddDir.size(); a++) { | |
532 | switch (sAddDir[a]) { | |
533 | case '/': | |
534 | if (sCurDir == "..") { | |
535 | sRet = sRet.substr(0, sRet.rfind('/')); | |
536 | } else if ((sCurDir != "") && (sCurDir != ".")) { | |
537 | sRet += "/" + sCurDir; | |
538 | } | |
539 | ||
540 | sCurDir = ""; | |
541 | break; | |
542 | default: | |
543 | sCurDir += sAddDir[a]; | |
544 | break; | |
545 | } | |
546 | } | |
547 | ||
548 | return (sRet.empty()) ? "/" : sRet; | |
549 | } | |
550 | ||
c7583c49 | 551 | CString CDir::CheckPathPrefix(const CString& sPath, const CString& sAdd, const CString& sHomeDir) { |
552 | CString sPrefix = sPath.Replace_n("//", "/").TrimRight_n("/") + "/"; | |
553 | CString sAbsolutePath = ChangeDir(sPrefix, sAdd, sHomeDir); | |
554 | ||
555 | if (sAbsolutePath.Left(sPrefix.length()) != sPrefix) | |
556 | return ""; | |
557 | return sAbsolutePath; | |
558 | } | |
559 | ||
b16e3ebe | 560 | bool CDir::MakeDir(const CString& sPath, mode_t iMode) { |
561 | CString sDir; | |
562 | VCString dirs; | |
563 | VCString::iterator it; | |
01bc68b1 | 564 | |
b16e3ebe | 565 | // Just in case someone tries this... |
8f1027d6 US |
566 | if (sPath.empty()) { |
567 | errno = ENOENT; | |
b16e3ebe | 568 | return false; |
8f1027d6 | 569 | } |
01bc68b1 | 570 | |
b16e3ebe | 571 | // If this is an absolute path, we need to handle this now! |
572 | if (sPath.Left(1) == "/") | |
573 | sDir = "/"; | |
01bc68b1 | 574 | |
b16e3ebe | 575 | // For every single subpath, do... |
576 | sPath.Split("/", dirs, false); | |
1d88f564 | 577 | for (it = dirs.begin(); it != dirs.end(); ++it) { |
b16e3ebe | 578 | // Add this to the path we already created |
579 | sDir += *it; | |
01bc68b1 | 580 | |
b16e3ebe | 581 | int i = mkdir(sDir.c_str(), iMode); |
01bc68b1 | 582 | |
b16e3ebe | 583 | if (i != 0) { |
584 | // All errors except EEXIST are fatal | |
585 | if (errno != EEXIST) | |
586 | return false; | |
01bc68b1 | 587 | |
b16e3ebe | 588 | // If it's EEXIST we have to make sure it's a dir |
589 | if (!CFile::IsDir(sDir)) | |
590 | return false; | |
01bc68b1 | 591 | } |
592 | ||
b16e3ebe | 593 | sDir += "/"; |
01bc68b1 | 594 | } |
595 | ||
b16e3ebe | 596 | // All went well |
597 | return true; | |
01bc68b1 | 598 | } |
599 | ||
d456374e | 600 | int CExecSock::popen2(int & iReadFD, int & iWriteFD, const CString & sCommand) { |
601 | int rpipes[2] = { -1, -1 }; | |
602 | int wpipes[2] = { -1, -1 }; | |
603 | iReadFD = -1; | |
604 | iWriteFD = -1; | |
605 | ||
b490b120 | 606 | if (pipe(rpipes) < 0) |
607 | return -1; | |
608 | ||
609 | if (pipe(wpipes) < 0) { | |
610 | close(rpipes[0]); | |
611 | close(rpipes[1]); | |
612 | return -1; | |
613 | } | |
f74ab87e | 614 | |
d456374e | 615 | int iPid = fork(); |
616 | ||
617 | if (iPid == -1) { | |
b490b120 | 618 | close(rpipes[0]); |
619 | close(rpipes[1]); | |
620 | close(wpipes[0]); | |
621 | close(wpipes[1]); | |
d456374e | 622 | return -1; |
623 | } | |
624 | ||
625 | if (iPid == 0) { | |
626 | close(wpipes[1]); | |
627 | close(rpipes[0]); | |
628 | dup2(wpipes[0], 0); | |
629 | dup2(rpipes[1], 1); | |
630 | dup2(rpipes[1], 2); | |
631 | close(wpipes[0]); | |
632 | close(rpipes[1]); | |
b490b120 | 633 | const char * pArgv[] = |
775df4f8 | 634 | { |
635 | "sh", | |
636 | "-c", | |
b490b120 | 637 | sCommand.c_str(), |
775df4f8 | 638 | NULL |
639 | }; | |
b490b120 | 640 | execvp("sh", (char * const *) pArgv); |
422ab328 | 641 | // if execvp returns, there was an error |
642 | perror("execvp"); | |
643 | exit(1); | |
d456374e | 644 | } |
645 | ||
646 | close(wpipes[0]); | |
647 | close(rpipes[1]); | |
648 | ||
649 | iWriteFD = wpipes[1]; | |
650 | iReadFD = rpipes[0]; | |
651 | ||
652 | return iPid; | |
653 | } | |
654 | ||
655 | void CExecSock::close2(int iPid, int iReadFD, int iWriteFD) { | |
b0a1714b | 656 | close(iReadFD); |
657 | close(iWriteFD); | |
0ad7756e | 658 | u_int iNow = time(NULL); |
659 | while (waitpid(iPid, NULL, WNOHANG) == 0) { | |
660 | if ((time(NULL) - iNow) > 5) | |
661 | break; // giveup | |
662 | usleep(100); | |
663 | } | |
d456374e | 664 | return; |
665 | } |