00001
00002
00003
00004
00005
00006
00007
00008 #include "DCPS/DdsDcps_pch.h"
00009
00010 #ifndef OPENDDS_SAFETY_PROFILE
00011
00012 #include "FileSystemStorage.h"
00013
00014 #include "ace/Dirent.h"
00015 #include "ace/Vector_T.h"
00016 #include "ace/OS_NS_sys_stat.h"
00017 #include "ace/OS_NS_macros.h"
00018 #include "ace/OS_NS_unistd.h"
00019 #include "ace/OS_NS_stdio.h"
00020
00021 #include <cstdio>
00022 #include <cstring>
00023 #include <stdexcept>
00024 #include <fstream>
00025
00026 typedef size_t String_Index_t;
00027
00028 namespace {
00029
00030 const size_t FSS_MAX_FILE_NAME = 150, FSS_MAX_FILE_NAME_ENCODED = 240,
00031 FSS_MAX_OVERFLOW_DIR = 9999;
00032 const ACE_TCHAR FSS_DEFAULT_FILE_NAME[] = ACE_TEXT("F00000000000000");
00033 const ACE_TCHAR FSS_DEFAULT_DIR_NAME[] = ACE_TEXT("D00000000000000");
00034
00035 void add_slash(ACE_TString& str)
00036 {
00037 if (str.length() == 0) return;
00038
00039 if (str[str.length() - 1] == ACE_TEXT('\\')) {
00040 str[str.length() - 1] = ACE_TEXT('/');
00041
00042 } else if (str[str.length() - 1] != ACE_TEXT('/')) {
00043 str += ACE_TEXT('/');
00044 }
00045 }
00046
00047
00048 bool increment(ACE_TString& logical)
00049 {
00050 for (size_t i = logical.length() - 1; i >= 1; --i) {
00051
00052
00053 if (logical[i] < 0x7F) {
00054 ++logical[i];
00055 return true;
00056 }
00057 }
00058
00059 return false;
00060 }
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 #if defined ACE_WIN32 && !defined ACE_HAS_WINCE
00071
00072 void fwd_slash_to_back_slash(ACE_WString& str)
00073 {
00074 for (String_Index_t idx = str.find(L'/'); idx != ACE_WString::npos;
00075 idx = str.find(L'/', idx + 1)) {
00076 str[idx] = L'\\';
00077 }
00078 }
00079
00080 bool is_relative(const ACE_TCHAR* path)
00081 {
00082 return !path[0] ||
00083 (path[1] != ACE_TEXT(':') &&
00084 (ACE_OS::strncmp(ACE_TEXT("\\\\?\\"), path, 4) != 0));
00085 }
00086
00087
00088 ACE_WString to_win32_long_path(const ACE_TCHAR* path)
00089 {
00090 ACE_WString wpath = ACE_TEXT_ALWAYS_WCHAR(path);
00091 fwd_slash_to_back_slash(wpath);
00092 ACE_WString dir;
00093
00094 if (is_relative(path)) {
00095 DWORD sz = ::GetCurrentDirectoryW(0, 0);
00096 ACE_Vector<wchar_t> cur(sz);
00097 cur.resize(sz, L'\0');
00098 ::GetCurrentDirectoryW(sz, &cur[0]);
00099 dir = &cur[0];
00100
00101 if (dir[dir.length() - 1] != L'\\') dir += L'\\';
00102 }
00103
00104 if (dir.substr(0, 4) != L"\\\\?\\" && wpath.substr(0, 4) != L"\\\\?\\")
00105 dir = L"\\\\?\\" + dir;
00106
00107 dir += wpath;
00108 return dir;
00109 }
00110
00111 int dds_mkdir(const ACE_TCHAR* path)
00112 {
00113 ACE_WString wpath = to_win32_long_path(path);
00114 ACE_WIN32CALL_RETURN(ACE_ADAPT_RETVAL(::CreateDirectoryW(wpath.c_str(), 0),
00115 ace_result_), int, -1);
00116 }
00117
00118 int dds_chdir(const ACE_TCHAR* path)
00119 {
00120
00121
00122 ACE_WString wpath = to_win32_long_path(path);
00123 wchar_t spath[MAX_PATH];
00124
00125 if (0 == ::GetShortPathNameW(wpath.c_str(), spath, MAX_PATH)) {
00126 throw std::runtime_error("GetShortPathNameW failed.");
00127 }
00128
00129 ACE_OSCALL_RETURN(::_wchdir(spath), int, -1);
00130 }
00131
00132 bool is_dir(const ACE_TCHAR* path)
00133 {
00134 ACE_WString wpath = to_win32_long_path(path);
00135 DWORD attrib = ::GetFileAttributesW(wpath.c_str());
00136
00137 if (attrib != INVALID_FILE_ATTRIBUTES) {
00138 return attrib & FILE_ATTRIBUTE_DIRECTORY;
00139 }
00140
00141 return false;
00142 }
00143
00144 int dds_rmdir(const ACE_TCHAR* path)
00145 {
00146 ACE_WString wpath = to_win32_long_path(path);
00147 ACE_WIN32CALL_RETURN(ACE_ADAPT_RETVAL(::RemoveDirectoryW(wpath.c_str()),
00148 ace_result_), int, -1);
00149 }
00150
00151 #else // !ACE_WIN32
00152
00153 inline int dds_mkdir(const ACE_TCHAR* path)
00154 {
00155 return ACE_OS::mkdir(path);
00156 }
00157
00158 inline int dds_chdir(const ACE_TCHAR* path)
00159 {
00160 return ACE_OS::chdir(path);
00161 }
00162
00163 inline bool is_dir(const ACE_TCHAR* path)
00164 {
00165 ACE_stat st;
00166 return ACE_OS::stat(path, &st) != -1 && (st.st_mode & S_IFDIR);
00167 }
00168
00169 inline int dds_rmdir(const ACE_TCHAR* path)
00170 {
00171 return ACE_OS::rmdir(path);
00172 }
00173
00174 #endif // ACE_WIN32
00175
00176 ACE_TString overflow_dir_name(unsigned int n)
00177 {
00178 ACE_TString of_name = ACE_TEXT("_overflow. /");
00179 ACE_TCHAR* buf = &of_name[10];
00180 ACE_OS::snprintf(buf, 5, ACE_TEXT("%04u"), n);
00181 of_name[14] = L'/';
00182 return of_name;
00183 }
00184
00185 struct CwdGuard {
00186 ACE_TString cwd_;
00187
00188 explicit CwdGuard(const ACE_TString& dir) {
00189 ACE_Vector<ACE_TCHAR> cwd_buf(128);
00190 cwd_buf.resize(128, ACE_TCHAR(0));
00191
00192 while (ACE_OS::getcwd(&cwd_buf[0], cwd_buf.size()) == 0) {
00193 if (errno == ERANGE) {
00194 cwd_buf.resize(cwd_buf.size() * 2, ACE_TCHAR(0));
00195
00196 } else break;
00197 }
00198
00199 if (cwd_buf[0]) cwd_ = &cwd_buf[0];
00200
00201 dds_chdir(dir.c_str());
00202 }
00203
00204 ~CwdGuard() {
00205 dds_chdir(cwd_.c_str());
00206 }
00207 };
00208
00209 void recursive_remove(const ACE_TString& dirname)
00210 {
00211 using namespace OpenDDS::FileSystemStorage;
00212 DDS_Dirent dir(dirname.c_str());
00213 {
00214 CwdGuard cg(dirname);
00215
00216 for (DDS_DIRENT* ent = dir.read(); ent; ent = dir.read()) {
00217 if (ent->d_name[0] == ACE_TEXT('.') && (!ent->d_name[1] ||
00218 (ent->d_name[1] == ACE_TEXT('.') && !ent->d_name[2]))) {
00219 continue;
00220 }
00221
00222 if (is_dir(ent->d_name)) {
00223 recursive_remove(ent->d_name);
00224
00225 } else {
00226 ACE_OS::unlink(ent->d_name);
00227 }
00228 }
00229 }
00230 dds_rmdir(dirname.c_str());
00231 }
00232
00233 }
00234
00235 namespace OpenDDS {
00236 namespace FileSystemStorage {
00237
00238 #ifdef ACE_WIN32
00239
00240
00241
00242 struct DDS_DIR {
00243
00244 wchar_t* directory_name_;
00245
00246
00247 HANDLE current_handle_;
00248
00249
00250 ACE_DIRENT* dirent_;
00251
00252
00253 WIN32_FIND_DATAW fdata_;
00254
00255
00256 int started_reading_;
00257 };
00258
00259
00260
00261 DDS_Dirent::DDS_Dirent(const ACE_TCHAR* path)
00262 : dirp_(0)
00263 {
00264 if (path) open(path);
00265 }
00266
00267 int DDS_Dirent::open(const ACE_TCHAR* path)
00268 {
00269 close();
00270 ACE_WString wpath =
00271 #ifdef ACE_HAS_WINCE
00272 path;
00273 #else
00274 to_win32_long_path(path);
00275 #endif
00276
00277
00278
00279 wchar_t extra[3] = {0, 0, 0};
00280 const wchar_t* filename = wpath.c_str();
00281
00282
00283 DWORD fileAttribute = ::GetFileAttributesW(filename);
00284
00285 if (fileAttribute == INVALID_FILE_ATTRIBUTES) {
00286 ACE_OS::set_errno_to_last_error();
00287 return -1;
00288 }
00289
00290 if (!(fileAttribute & FILE_ATTRIBUTE_DIRECTORY)) {
00291 errno = ENOTDIR;
00292 return -1;
00293 }
00294
00295 size_t const lastchar = ACE_OS::strlen(filename);
00296
00297 if (lastchar > 0) {
00298 if (filename[lastchar-1] != L'*') {
00299 if (filename[lastchar-1] != L'/' && filename[lastchar-1] != L'\\')
00300 ACE_OS::strcpy(extra, L"\\*");
00301
00302 else
00303 ACE_OS::strcpy(extra, L"*");
00304 }
00305 }
00306
00307 ACE_NEW_RETURN(dirp_, DDS_DIR, -1);
00308 ACE_NEW_RETURN(dirp_->directory_name_,
00309 wchar_t[lastchar + ACE_OS::strlen(extra) + 1],
00310 -1);
00311 ACE_OS::strcpy(dirp_->directory_name_, filename);
00312
00313 if (extra[0])
00314 ACE_OS::strcat(dirp_->directory_name_, extra);
00315
00316 dirp_->current_handle_ = INVALID_HANDLE_VALUE;
00317 dirp_->started_reading_ = 0;
00318 dirp_->dirent_ = 0;
00319 return 0;
00320 }
00321
00322 DDS_DIRENT* DDS_Dirent::read()
00323 {
00324 if (!dirp_) return 0;
00325
00326
00327
00328
00329
00330 if (dirp_->dirent_ != 0) {
00331 #ifdef ACE_HAS_TCHAR_DIRENT
00332 ACE_OS::free(dirp_->dirent_->d_name);
00333 #endif
00334 ACE_OS::free(dirp_->dirent_);
00335 dirp_->dirent_ = 0;
00336 }
00337
00338 if (!dirp_->started_reading_) {
00339 dirp_->current_handle_ = ::FindFirstFileW(dirp_->directory_name_,
00340 &dirp_->fdata_);
00341 dirp_->started_reading_ = 1;
00342
00343 } else {
00344 int retval = ::FindNextFileW(dirp_->current_handle_, &dirp_->fdata_);
00345
00346 if (retval == 0) {
00347
00348 ::FindClose(dirp_->current_handle_);
00349 dirp_->current_handle_ = INVALID_HANDLE_VALUE;
00350 }
00351 }
00352
00353 if (dirp_->current_handle_ != INVALID_HANDLE_VALUE) {
00354 dirp_->dirent_ = (DDS_DIRENT*) ACE_Allocator::instance()->malloc(sizeof(DDS_DIRENT));
00355
00356 if (dirp_->dirent_ != 0) {
00357 #ifdef ACE_HAS_TCHAR_DIRENT
00358 dirp_->dirent_->d_name =
00359 (ACE_TCHAR*) ACE_Allocator::instance()->malloc((ACE_OS::strlen(dirp_->fdata_.cFileName)
00360 + 1) * sizeof(ACE_TCHAR));
00361 ACE_OS::strcpy(dirp_->dirent_->d_name,
00362 ACE_TEXT_WCHAR_TO_TCHAR(dirp_->fdata_.cFileName));
00363 #else // MinGW: d_name is a fixed-size char array
00364 ACE_OS::strncpy(dirp_->dirent_->d_name,
00365 ACE_Wide_To_Ascii(dirp_->fdata_.cFileName).char_rep(),
00366 sizeof(dirp_->dirent_->d_name));
00367 #endif
00368 dirp_->dirent_->d_reclen = sizeof(DDS_DIRENT);
00369 }
00370
00371 return dirp_->dirent_;
00372
00373 } else
00374 return 0;
00375 }
00376
00377 void DDS_Dirent::close()
00378 {
00379 if (dirp_) {
00380 if (dirp_->current_handle_ != INVALID_HANDLE_VALUE)
00381 ::FindClose(dirp_->current_handle_);
00382
00383 dirp_->current_handle_ = INVALID_HANDLE_VALUE;
00384 dirp_->started_reading_ = 0;
00385
00386 if (dirp_->dirent_ != 0) {
00387 #ifdef ACE_HAS_TCHAR_DIRENT
00388 ACE_OS::free(dirp_->dirent_->d_name);
00389 #endif
00390 ACE_OS::free(dirp_->dirent_);
00391 }
00392
00393 dirp_ = 0;
00394 }
00395 }
00396
00397 DDS_Dirent::~DDS_Dirent()
00398 {
00399 close();
00400 }
00401
00402 #elif defined ACE_USES_WCHAR // non-Win32 uses-WChar
00403
00404 struct DDS_DIR {
00405 ACE_DIR* real_dir_;
00406 DDS_DIRENT ent_;
00407
00408 DDS_DIR() : real_dir_(), ent_() {}
00409 };
00410
00411 DDS_Dirent::DDS_Dirent(const ACE_TCHAR* path)
00412 : dirp_(new DDS_DIR)
00413 {
00414 if (path) open(path);
00415 }
00416
00417 int DDS_Dirent::open(const ACE_TCHAR* path)
00418 {
00419 close();
00420 return (dirp_->real_dir_ = ACE_OS::opendir(path)) == 0 ? -1 : 0;
00421 }
00422
00423 DDS_DIRENT* DDS_Dirent::read()
00424 {
00425 if (!dirp_->real_dir_) return 0;
00426
00427 dirp_->ent_.real_dirent_ = ACE_OS::readdir(dirp_->real_dir_);
00428
00429 if (!dirp_->ent_.real_dirent_) return 0;
00430
00431 ACE_OS::free(dirp_->ent_.d_name);
00432 dirp_->ent_.d_name =
00433 ACE_OS::strdup(ACE_TEXT_CHAR_TO_TCHAR(dirp_->ent_.real_dirent_->d_name));
00434 return &dirp_->ent_;
00435 }
00436
00437 void DDS_Dirent::close()
00438 {
00439 if (dirp_->real_dir_) {
00440 ACE_OS::closedir(dirp_->real_dir_);
00441 ACE_OS::free(dirp_->ent_.d_name);
00442 }
00443
00444 dirp_->real_dir_ = 0;
00445 }
00446
00447 DDS_Dirent::~DDS_Dirent()
00448 {
00449 close();
00450 delete dirp_;
00451 }
00452
00453 #endif // ACE_WIN32
00454
00455
00456
00457 File::File(const ACE_TString& fname_phys, const ACE_TString& logical,
00458 Directory* parent)
00459 : physical_file_()
00460 , physical_dir_()
00461 , logical_relative_(logical)
00462 , parent_(parent, false)
00463 {
00464 String_Index_t last_slash = fname_phys.rfind(ACE_TEXT('/'));
00465
00466 if (last_slash == ACE_TString::npos) {
00467 physical_file_ = fname_phys;
00468 physical_dir_ = ACE_TEXT(".");
00469
00470 } else {
00471 physical_file_ = fname_phys.c_str() + last_slash + 1;
00472 physical_dir_.set(fname_phys.c_str(), last_slash, true);
00473 }
00474 }
00475
00476 bool File::write(std::ofstream& stream)
00477 {
00478 CwdGuard cg(physical_dir_);
00479 stream.open(ACE_TEXT_ALWAYS_CHAR(physical_file_.c_str()),
00480 ios::binary | ios::out);
00481 return !stream.bad() && !stream.fail();
00482 }
00483
00484 bool File::read(std::ifstream& stream)
00485 {
00486 CwdGuard cg(physical_dir_);
00487 stream.open(ACE_TEXT_ALWAYS_CHAR(physical_file_.c_str()),
00488 ios::binary | ios::in);
00489 return !stream.bad() && !stream.fail();
00490 }
00491
00492 bool File::remove()
00493 {
00494 int unlink_result = -1;
00495 {
00496 CwdGuard cg(physical_dir_);
00497 unlink_result = ACE_OS::unlink(physical_file_.c_str());
00498 }
00499
00500 if (unlink_result != -1) {
00501 parent_->removing(logical_relative_, true);
00502 return true;
00503 }
00504
00505 return false;
00506 }
00507
00508 OPENDDS_STRING File::name() const
00509 {
00510 return ACE_TEXT_ALWAYS_CHAR(logical_relative_.c_str());
00511 }
00512
00513
00514
00515 Directory::Ptr Directory::create(const char* dirname)
00516 {
00517 return new Directory(ACE_TEXT_CHAR_TO_TCHAR(dirname), ACE_TEXT(""), 0);
00518 }
00519
00520 ACE_TString Directory::full_path(const ACE_TString& relative) const
00521 {
00522 return physical_dirname_ + relative;
00523 }
00524
00525 Directory::FileIterator Directory::begin_files()
00526 {
00527 return FileIterator(files_.begin(), this);
00528 }
00529
00530 Directory::FileIterator Directory::end_files()
00531 {
00532 return FileIterator(files_.end(), this);
00533 }
00534
00535 File::Ptr Directory::get_file(const char* name)
00536 {
00537 if (std::strlen(name) >= FSS_MAX_FILE_NAME) {
00538 throw std::runtime_error("file name too long");
00539 }
00540
00541 ACE_TString t_name(ACE_TEXT_CHAR_TO_TCHAR(name));
00542 Map::iterator it = files_.find(t_name);
00543
00544 if (it == files_.end()) {
00545 return make_new_file(t_name);
00546
00547 } else {
00548 return new File(full_path(it->second), it->first, this);
00549 }
00550 }
00551
00552 File::Ptr Directory::make_new_file(const ACE_TString& t_name)
00553 {
00554 if (dirs_.find(t_name) != dirs_.end()) {
00555 throw std::runtime_error("Can't create a file with the same name as "
00556 "an existing directory.");
00557 }
00558
00559 ACE_TString phys = add_entry() + b32h_encode(t_name.c_str());
00560 files_[t_name] = phys;
00561
00562 CwdGuard cg(physical_dirname_);
00563
00564 std::FILE* fh = std::fopen(ACE_TEXT_ALWAYS_CHAR(phys.c_str()), "w");
00565
00566 if (!fh) throw std::runtime_error("Can't create the file");
00567
00568 std::fclose(fh);
00569 return new File(physical_dirname_ + phys, t_name, this);
00570 }
00571
00572 File::Ptr Directory::create_next_file()
00573 {
00574 ACE_TString logical;
00575
00576 if (files_.empty()) {
00577 logical = FSS_DEFAULT_FILE_NAME;
00578
00579 } else {
00580 Map::iterator last = --files_.end();
00581 logical = last->first;
00582
00583 if (!increment(logical)) {
00584 throw std::runtime_error("out of range for create_next_file");
00585 }
00586 }
00587
00588 return make_new_file(logical);
00589 }
00590
00591 Directory::DirectoryIterator Directory::begin_dirs()
00592 {
00593 return DirectoryIterator(dirs_.begin(), this);
00594 }
00595
00596 Directory::DirectoryIterator Directory::end_dirs()
00597 {
00598 return DirectoryIterator(dirs_.end(), this);
00599 }
00600
00601 Directory::Ptr Directory::get_dir(const OPENDDS_VECTOR(OPENDDS_STRING)& path)
00602 {
00603 Directory::Ptr dir(this, false);
00604 typedef OPENDDS_VECTOR(OPENDDS_STRING)::const_iterator iterator;
00605
00606 for (iterator iter = path.begin(), end = path.end(); iter != end; ++iter) {
00607 dir = dir->get_subdir(iter->c_str());
00608 }
00609
00610 return dir;
00611 }
00612
00613 Directory::Ptr Directory::get_subdir(const char* name)
00614 {
00615 ACE_TString t_name = ACE_TEXT_CHAR_TO_TCHAR(name);
00616 Map::iterator it = dirs_.find(t_name);
00617
00618 if (it == dirs_.end()) {
00619 return make_new_subdir(t_name);
00620
00621 } else {
00622 return new Directory(full_path(it->second), it->first, this);
00623 }
00624 }
00625
00626 Directory::Ptr Directory::create_next_dir()
00627 {
00628 ACE_TString logical;
00629
00630 if (dirs_.empty()) {
00631 logical = FSS_DEFAULT_DIR_NAME;
00632
00633 } else {
00634 Map::iterator last = --dirs_.end();
00635 logical = last->first;
00636
00637 if (!increment(logical)) {
00638 throw std::runtime_error("out of range for create_next_dir");
00639 }
00640 }
00641
00642 return make_new_subdir(logical);
00643 }
00644
00645 Directory::Ptr Directory::make_new_subdir(const ACE_TString& t_name)
00646 {
00647 if (files_.find(t_name) != files_.end()) {
00648 throw std::runtime_error("Can't create a directory with the same "
00649 "name as an existing file.");
00650 }
00651
00652 ACE_TString logical(t_name.c_str(),
00653 (std::min)(FSS_MAX_FILE_NAME, t_name.length()));
00654 ACE_TString phys_prefix = add_entry();
00655 ACE_TString phys_base = b32h_encode(logical.c_str());
00656
00657 if (t_name.length() >= FSS_MAX_FILE_NAME) {
00658 unsigned int& counter = long_names_[phys_prefix + phys_base];
00659
00660 if (counter == 99999) {
00661 throw std::runtime_error("Long directory name out of range");
00662 }
00663
00664 phys_base += ACE_TEXT(". X");
00665 ACE_TCHAR* buf = &phys_base[0] + phys_base.length() - 6;
00666 ACE_OS::snprintf(buf, 6, ACE_TEXT("%05u"), counter++);
00667 phys_base = phys_base.substr(0, phys_base.length() - 1);
00668 }
00669
00670 ACE_TString phys = phys_prefix + phys_base;
00671 dirs_[t_name] = phys;
00672 {
00673 CwdGuard cg(physical_dirname_);
00674
00675 if (dds_mkdir(phys.c_str()) == -1) {
00676 throw std::runtime_error("Can't create directory");
00677 }
00678
00679 if ((phys_prefix.length() > 0 && dds_chdir(phys_prefix.c_str()) == -1)
00680 || dds_chdir(phys_base.c_str()) == -1) {
00681 dds_rmdir(phys.c_str());
00682 throw std::runtime_error("Can't change to newly created directory");
00683 }
00684
00685 std::ofstream fn("_fullname");
00686 fn << t_name << '\n';
00687 }
00688 return new Directory(physical_dirname_ + phys, t_name, this);
00689 }
00690
00691 ACE_TString Directory::add_entry()
00692 {
00693 if (overflow_.empty()) {
00694 overflow_[0] = 1;
00695 return ACE_TEXT("");
00696 }
00697
00698 typedef OPENDDS_MAP(unsigned int, unsigned int)::iterator iterator;
00699
00700 bool found_gap(false);
00701 unsigned int last_seen(0), unused_bucket(0);
00702
00703 for (iterator iter = overflow_.begin(), end = overflow_.end();
00704 iter != end; ++iter) {
00705 if (iter->second < OPENDDS_FILESYSTEMSTORAGE_MAX_FILES_PER_DIR) {
00706 ++iter->second;
00707
00708 if (iter->first == 0) return ACE_TEXT("");
00709
00710 return overflow_dir_name(iter->first);
00711 }
00712
00713 if (!found_gap && iter->first > last_seen + 1) {
00714 found_gap = true;
00715 unused_bucket = last_seen + 1;
00716 }
00717
00718 last_seen = iter->first;
00719 }
00720
00721 if (!found_gap) {
00722 if (last_seen == FSS_MAX_OVERFLOW_DIR) {
00723 throw std::runtime_error("Overflow serial # out of range.");
00724 }
00725
00726 unused_bucket = last_seen + 1;
00727 }
00728
00729 overflow_[unused_bucket] = 1;
00730 ACE_TString dir_name = overflow_dir_name(unused_bucket);
00731 CwdGuard cg(physical_dirname_);
00732
00733 if (dds_mkdir(dir_name.c_str()) == -1) {
00734 throw std::runtime_error("Can't create overflow directory");
00735 }
00736
00737 return dir_name;
00738 }
00739
00740 void Directory::remove()
00741 {
00742 if (!parent_.is_nil()) parent_->removing(logical_dirname_, false);
00743
00744 parent_ = 0;
00745 recursive_remove(physical_dirname_);
00746 overflow_.clear();
00747 files_.clear();
00748 dirs_.clear();
00749 long_names_.clear();
00750 }
00751
00752 OPENDDS_STRING Directory::name() const
00753 {
00754 return ACE_TEXT_ALWAYS_CHAR(logical_dirname_.c_str());
00755 }
00756
00757 Directory::Directory(const ACE_TString& dirname, const ACE_TString& logical,
00758 Directory* parent)
00759 : parent_(parent, false)
00760 , physical_dirname_(dirname)
00761 , logical_dirname_(logical)
00762 {
00763 add_slash(physical_dirname_);
00764
00765 bool ok(true);
00766 DDS_Dirent dir;
00767
00768 if (dir.open(physical_dirname_.c_str()) == -1) {
00769 ok = false;
00770
00771 if (errno == ENOENT && dds_mkdir(physical_dirname_.c_str()) != -1
00772 && dir.open(physical_dirname_.c_str()) != -1) {
00773 ok = true;
00774 }
00775 }
00776
00777 if (!ok) throw std::runtime_error("Can't open or create directory");
00778
00779 scan_dir(ACE_TEXT(""), dir, 0);
00780 }
00781
00782 void Directory::scan_dir(const ACE_TString& relative, DDS_Dirent& dir,
00783 unsigned int overflow_index)
00784 {
00785 ACE_TString path = physical_dirname_ + relative;
00786 add_slash(path);
00787
00788 while (DDS_DIRENT* ent = dir.read()) {
00789 if (ent->d_name[0] == ACE_TEXT('.') && (!ent->d_name[1] ||
00790 (ent->d_name[1] == ACE_TEXT('.') && !ent->d_name[2]))) {
00791 continue;
00792 }
00793
00794 ACE_TString file = path + ent->d_name;
00795
00796 if (is_dir(file.c_str())) {
00797 ACE_TString phys(relative);
00798 add_slash(phys);
00799 phys += ent->d_name;
00800
00801 if (ACE_OS::strncmp(ent->d_name, ACE_TEXT("_overflow."), 10) == 0) {
00802 unsigned int n = ACE_OS::atoi(ent->d_name + 10);
00803 DDS_Dirent overflow(file.c_str());
00804 scan_dir(ent->d_name, overflow, n);
00805
00806 } else if (ACE_OS::strlen(ent->d_name) <= FSS_MAX_FILE_NAME_ENCODED) {
00807 dirs_[b32h_decode(ent->d_name)] = phys;
00808 ++overflow_[overflow_index];
00809
00810 } else {
00811 CwdGuard cg(file);
00812 std::ifstream fn("_fullname");
00813 OPENDDS_STRING fullname;
00814
00815 if (!std::getline(fn, fullname)) {
00816 throw std::runtime_error("Can't read .../_fullname");
00817 }
00818
00819 ACE_TString full_t(ACE_TEXT_CHAR_TO_TCHAR(fullname.c_str()));
00820 dirs_[full_t] = phys;
00821 ++overflow_[overflow_index];
00822
00823 String_Index_t idx = phys.rfind(ACE_TEXT('.'));
00824
00825 if (idx == ACE_TString::npos) {
00826 throw std::runtime_error("Badly formatted long dir name");
00827 }
00828
00829 ACE_TString prefix(phys.c_str(), idx);
00830 unsigned int serial = ACE_OS::atoi(&phys[idx + 1]);
00831 unsigned int& counter = long_names_[prefix];
00832
00833 if (serial >= counter) counter = serial + 1;
00834 }
00835
00836 } else {
00837 if (ent->d_name[0] != ACE_TEXT('_')) {
00838 files_[b32h_decode(ent->d_name)] = ent->d_name;
00839 ++overflow_[overflow_index];
00840 }
00841 }
00842 }
00843 }
00844
00845 void Directory::removing(const ACE_TString& child, bool file)
00846 {
00847 Map& m = file ? files_ : dirs_;
00848 Map::iterator iter = m.find(child);
00849
00850 if (iter == m.end()) return;
00851
00852 const ACE_TString& phys = iter->second;
00853 String_Index_t idx = phys.find(ACE_TEXT("_overflow."));
00854 unsigned int bucket = (idx == 0 ? ACE_OS::atoi(&phys[idx + 10]) : 0);
00855
00856 if (--overflow_[bucket] == 0 && bucket > 0) {
00857 overflow_.erase(bucket);
00858 idx = phys.find(ACE_TEXT('/'));
00859 ACE_TString ov_dir = physical_dirname_ + ACE_TString(phys.c_str(), idx);
00860 dds_rmdir(ov_dir.c_str());
00861 }
00862
00863 m.erase(iter);
00864 }
00865
00866
00867
00868 ACE_TString b32h_encode(const ACE_TCHAR* decoded)
00869 {
00870 static const ACE_TCHAR lookup[] =
00871 ACE_TEXT("0123456789ABCDEFGHIJKLMNOPQRSTUV");
00872 static const ACE_TCHAR padding[] = ACE_TEXT("======");
00873 static const size_t enc[] = {0, 2, 4, 5, 7};
00874 ACE_TString encoded;
00875
00876 for (size_t len = ACE_OS::strlen(decoded); *decoded; decoded += 5, len -= 5) {
00877 ACE_UINT64 chunk = 0;
00878
00879 for (size_t i(0); i < 5 && i < len; ++i) {
00880 chunk |= static_cast<ACE_UINT64>(decoded[i] & 0xFF) << ((4 - i) * 8);
00881 }
00882
00883 size_t limit = (len < 5) ? enc[len] : 8;
00884
00885 for (size_t i(0); i < limit; ++i) {
00886 unsigned char val =
00887 static_cast<unsigned char>(chunk >>((7 - i) * 5)) & 0x1F;
00888 encoded += lookup[val];
00889 }
00890
00891 if (len < 5) {
00892 encoded.append(padding, 8 - enc[len]);
00893 return encoded;
00894 }
00895 }
00896
00897 return encoded;
00898 }
00899
00900 ACE_TString b32h_decode(const ACE_TCHAR* encoded)
00901 {
00902
00903 static const size_t dec[] = {0, 0, 1, 0, 2, 3, 0, 4};
00904 ACE_TString decoded;
00905
00906 for (; *encoded; encoded += 8) {
00907 ACE_UINT64 chunk = 0;
00908 size_t i = 0;
00909
00910 for (; i < 8 && encoded[i] != ACE_TEXT('='); ++i) {
00911 char idx = (encoded[i] <= ACE_TEXT('9'))
00912 ? (encoded[i] - ACE_TEXT('0'))
00913 : (10 + encoded[i] - ACE_TEXT('A'));
00914 chunk |= static_cast<ACE_UINT64>(idx) << ((7 - i) * 5);
00915 }
00916
00917 size_t limit = (encoded[i] == ACE_TEXT('=')) ? dec[i] : 5;
00918
00919 for (size_t j(0); j < limit; ++j) {
00920 decoded += static_cast<ACE_TCHAR>(chunk >>((4 - j) * 8)) & 0xFF;
00921 }
00922 }
00923
00924 return decoded;
00925 }
00926
00927 }
00928 }
00929
00930 #endif