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;
}
Example #2
0
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;
}