Ticket #1184 (new defect)

Opened 4 years ago

Last modified 2 years ago

refactoring of utils::Directory relies on non-portable code

Reported by: anonymous Owned by: rakshasa
Priority: normal Component: libtorrent
Version: HEAD Severity: normal
Keywords: Cc:

Description

I'm just quoting from  here , but the change in (i believe) [1022] introduced non-posix code that makes compiling on Solaris impossible. According to  the posix standard, the only field you can rely on dirent having is d_name. Solaris, indeed, does not have this field, and apparently you're supposed to figure out if something is a directory or not by using stat().

I feel like a jerk for pointing it out, but there it is.

Change History

Changed 4 years ago by peter@shortbus.org

and i forgot to fill in my email address. this ticket is from me.

Changed 4 years ago by peter@shortbus.org

... and it's for rtorrent. I'm a sharp knife today.

Changed 4 years ago by anonymous

This has already been fixed in the latest revision.

Changed 4 years ago by rakshasa

I won't bother wrapping the d_type access atm, though the rest is fixed. If an arch doesn't have even that, then the person who wants to compile for it will have to send a patch or something.

Changed 4 years ago by Peter Woodman <peter@shortbus.org>

Okay. I'm on it. :)

Changed 4 years ago by Matson

struct _transform_filename {                                                                                                 
  struct stat *s;                                                                                                            
  void operator () (utils::directory_entry& entry) {                                                                         
    stat(entry.d_name.c_str(), s);                                                                                           
    if (s->st_mode & S_IFDIR) {                                                                                              
      entry.d_name += '/';                                                                                                   
    }                                                                                                                        
  }                                                                                                                          
};                                                                                                                    

       

Changed 4 years ago by anonymous

I'm not familiar with stat() usage, but I'm pretty sure something is off there. You'd need to initialise the pointer before you pass it to stat, otherwise it will write into unknown memory.

I recommend struct stat s; stat(entry.d_name.c_str(), &s);

Changed 3 years ago by bju@stacken.kth.se

These are the changes I made to compile rtorrent-0.8.2.tar.gz on Solaris 10 SPARC64 (gcc 3.4.3).

Everything seems to run fine and CPU usage is alot less than my previous python client.

in src/input/path_input.cc:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/dirent.h>

struct _transform_filename {
  void operator () (utils::directory_entry& entry) {
    if (S_ISDIR(entry.d_type))
      entry.d_name += '/';
  }
};

in src/utils/directory.cc:

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>


bool
Directory::update(int flags) {
  if (m_path.empty())
    throw torrent::input_error("Directory::update() tried to open an empty path.");

  std::string path=rak::path_expand(m_path);
  
  DIR* d = opendir(path.c_str());
  
  if (d == NULL)
    return false;

  struct dirent* entry;

  while ((entry = readdir(d)) != NULL) {
    if ((flags & update_hide_dot) && entry->d_name[0] == '.')
      continue;
    
    std::string full_path=path+'/';
    full_path+=entry->d_name;
    
    struct stat sb;
    if(stat(full_path.c_str(),&sb))
      continue;

    iterator itr = base_type::insert(end(),value_type());
    
    itr->d_fileno = sb.st_ino;
    itr->d_reclen = 0; // doesn't seem to get used anywhere.
    itr->d_type   = sb.st_mode;
    
    
#ifdef DIRENT_NAMLEN_EXISTS_FOOBAR
    itr->d_name   = std::string(entry->d_name, entry->d_name + entry->d_namlen);
#else
    itr->d_name   = std::string(entry->d_name);
#endif
  }

  closedir(d);

  if (flags & update_sort)
    std::sort(begin(), end());

  return true;
}

in src/rpc/scgi.cc: change AF_LOCAL to AF_UNIX

in src/signal_handler.h: use signal.h instead off sys/signal.h

Thank you for this great software / Björn

Changed 2 years ago by anonymous

how many of these changes require #ifdef sun (i.e. are solaris specific) and how many are cross-platform compatible (within reason)?

Note: See TracTickets for help on using tickets.