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