bool RPG_Net_Server_Common_Tools::getNextLogFilename (const std::string& directory_in, std::string& FQLogFilename_out) { RPG_TRACE (ACE_TEXT ("RPG_Net_Server_Common_Tools::getNextLogFilename")); // initialize return value(s) FQLogFilename_out.resize (0); // sanity check(s): log directory exists ? // No ? --> try to create it then ! if (!Common_File_Tools::isDirectory (directory_in)) { if (!Common_File_Tools::createDirectory (directory_in)) { ACE_DEBUG ((LM_ERROR, ACE_TEXT ("failed to Common_File_Tools::createDirectory(\"%s\"), aborting\n"), ACE_TEXT (directory_in.c_str ()))); return false; } // end IF ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("created directory: \"%s\"...\n"), ACE_TEXT (directory_in.c_str ()))); } // end IF // construct correct logfilename... FQLogFilename_out = directory_in; FQLogFilename_out += ACE_DIRECTORY_SEPARATOR_CHAR_A; std::string logFileName = ACE_TEXT_ALWAYS_CHAR (RPG_NET_SERVER_LOG_FILENAME_PREFIX); logFileName += ACE_TEXT_ALWAYS_CHAR (COMMON_LOG_FILENAME_SUFFIX); FQLogFilename_out += logFileName; // retrieve all existing logs and sort them alphabetically... ACE_Dirent_Selector entries; int result = entries.open (directory_in.c_str (), &RPG_Net_Server_Common_Tools::selector, &RPG_Net_Server_Common_Tools::comparator); if (result == -1) { ACE_DEBUG ((LM_ERROR, ACE_TEXT ("failed to ACE_Dirent_Selector::open(\"%s\"): \"%s\", aborting\n"), ACE_TEXT (directory_in.c_str ()), ACE_TEXT (ACE_OS::strerror (ACE_OS::last_error())))); return false; } // end IF // ACE_DEBUG ((LM_DEBUG, // ACE_TEXT ("found %d logfiles...\n"), // entries.length ())); // OK: iterate over the entries and perform some magic... // *NOTE*: entries have been sorted alphabetically: // 1 current 2 4 3 --> current 1 2 3 4 // *TODO*: some malicious user could inject "fake" logfiles which can // "confuse" this algorithm... // skip handling of "<PREFIX><SUFFIX>" (if found)... // *NOTE*: <PREFIX><SUFFIX> will become <PREFIX>_1<SUFFIX>... bool found_current = false; // sscanf settings int number = 0; int return_val = -1; std::string format_string ("%d"); format_string += ACE_TEXT_ALWAYS_CHAR (COMMON_LOG_FILENAME_SUFFIX); std::stringstream converter; for (int i = entries.length () - 1, index = RPG_Net_Server_Common_Tools::maxNumberOfLogFiles_ - 1; i >= 0; i--) { // perform "special treatment" if "<PREFIX><SUFFIX>" found... // *TODO*: do this in C++... if (ACE_OS::strcmp (entries[i]->d_name, logFileName.c_str ()) == 0) { found_current = true; // skip this one for now continue; } // end IF // scan number... try { // *TODO*: do this in C++... return_val = ::sscanf (entries[i]->d_name + // skip some characters... (ACE_OS::strlen (ACE_TEXT_ALWAYS_CHAR (RPG_NET_SERVER_LOG_FILENAME_PREFIX)) + 1), format_string.c_str (), &number); if (return_val != 1) { if (return_val != 0) { ACE_DEBUG ((LM_ERROR, ACE_TEXT ("::sscanf() failed for \"%s\": \"%s\", continuing\n"), entries[i]->d_name, ACE_TEXT (ACE_OS::strerror (ACE_OS::last_error ())))); } // end IF continue; } // end IF } catch (...) { ACE_DEBUG ((LM_ERROR, ACE_TEXT ("caught exception in ::sscanf() for \"%s\": \"%s\", continuing\n"), entries[i]->d_name, ACE_TEXT (ACE_OS::strerror (ACE_OS::last_error ())))); continue; } // adjust the index, if the number is smaller than max if (number < index) index = number + 1; // if the number is bigger than the max AND we have more than enough logs --> delete it ! if ((static_cast<unsigned long> (number) >= (RPG_Net_Server_Common_Tools::maxNumberOfLogFiles_ - 1)) && (static_cast<unsigned long> (entries.length()) >= RPG_Net_Server_Common_Tools::maxNumberOfLogFiles_)) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("removing surplus logfile \"%s\"...\n"), entries[i]->d_name)); // clean up std::string FQfilename = directory_in; FQfilename += ACE_DIRECTORY_SEPARATOR_CHAR_A; FQfilename += entries[i]->d_name; Common_File_Tools::deleteFile (FQfilename); continue; } // end IF // logrotate file... std::string oldFQfilename = directory_in; oldFQfilename += ACE_DIRECTORY_SEPARATOR_CHAR_A; oldFQfilename += entries[i]->d_name; std::string newFQfilename = directory_in; newFQfilename += ACE_DIRECTORY_SEPARATOR_CHAR_A; newFQfilename += ACE_TEXT_ALWAYS_CHAR (RPG_NET_SERVER_LOG_FILENAME_PREFIX); newFQfilename += ACE_TEXT_ALWAYS_CHAR ("_"); converter.clear (); converter.str (ACE_TEXT_ALWAYS_CHAR ("")); converter << index; newFQfilename += converter.str (); newFQfilename += ACE_TEXT_ALWAYS_CHAR (COMMON_LOG_FILENAME_SUFFIX); // *IMPORTANT NOTE*: last parameter affects Win32 behaviour only, // see "ace/OS_NS_stdio.inl" ! if (ACE_OS::rename (oldFQfilename.c_str (), newFQfilename.c_str (), -1)) { ACE_DEBUG ((LM_ERROR, ACE_TEXT ("failed to ACE_OS::rename() \"%s\" to \"%s\": \"%s\", aborting\n"), ACE_TEXT (oldFQfilename.c_str ()), ACE_TEXT (newFQfilename.c_str ()), ACE_TEXT (ACE_OS::strerror (ACE_OS::last_error ())))); return false; } // end IF ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("renamed file \"%s\" to \"%s\"...\n"), ACE_TEXT (oldFQfilename.c_str ()), ACE_TEXT (newFQfilename.c_str ()))); index--; } // end FOR if (found_current) { std::string newFQfilename = directory_in; newFQfilename += ACE_DIRECTORY_SEPARATOR_CHAR_A; newFQfilename += ACE_TEXT_ALWAYS_CHAR (RPG_NET_SERVER_LOG_FILENAME_PREFIX); newFQfilename += ACE_TEXT_ALWAYS_CHAR ("_1"); newFQfilename += ACE_TEXT_ALWAYS_CHAR (COMMON_LOG_FILENAME_SUFFIX); // *TODO*: last parameter affects Win32 behaviour only, see "ace/OS_NS_stdio.inl" ! if (ACE_OS::rename (FQLogFilename_out.c_str (), newFQfilename.c_str (), -1)) { ACE_DEBUG ((LM_ERROR, ACE_TEXT ("failed to ACE_OS::rename() \"%s\" to \"%s\": \"%m\", aborting\n"), ACE_TEXT (FQLogFilename_out.c_str ()), ACE_TEXT (newFQfilename.c_str ()))); return false; } // end IF ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("renamed file \"%s\" to \"%s\"...\n"), ACE_TEXT (FQLogFilename_out.c_str ()), ACE_TEXT (newFQfilename.c_str ()))); } // end IF return true; }
static int dirent_selector_test (void) { int status; int n; int error = 0; const ACE_TCHAR *test_dir = TestDir.c_str (); ACE_Dirent_Selector sds; // Pass in functions that'll specify the selection criteria. status = sds.open (test_dir, selector, comparator); if (status == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%s, %p\n"), test_dir, ACE_TEXT ("open")), -1); // We should only have located ourselves! if (sds.length () != 1) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("selected %d entries in %s, should be 1\n"), sds.length (), test_dir)); error = 1; } for (n = 0; n < sds.length (); ++n) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Sorted: %d: %C\n"), n, sds[n]->d_name)); status = sds.close (); if (status == -1) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("after selecting, %p\n"), ACE_TEXT ("close"))); error = 1; } ACE_Dirent_Selector ds; // Don't specify any selection criteria. status = ds.open (test_dir); if (status == -1) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("%s w/o selection criteria; %p\n"), test_dir, ACE_TEXT ("open"))); error = 1; } // We counted the entries earlier by hand; should be the same here. if (entrycount != ds.length ()) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("Counted %d entries in %s but selector says %d\n"), entrycount, test_dir, ds.length ())); error = 1; } for (n = 0; n < ds.length (); ++n) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Entry %d: %C\n"), n, ds[n]->d_name)); if (ds.close () == -1) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("w/o selection criteria; %p\n"), ACE_TEXT ("close"))); error = 1; } return error ? -1 : 0; }