Browse Source

Upgrade session root parsing to fts. Nested session as tree are now handled correctly

tags/v1.5.0
Nils 4 years ago
parent
commit
19880abe21
1 changed files with 118 additions and 30 deletions
  1. +118
    -30
      src/nsmd.cpp

+ 118
- 30
src/nsmd.cpp View File

@@ -39,14 +39,12 @@
#include <sys/signalfd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <time.h>
#include <libgen.h>
#include <dirent.h>
#include <ftw.h>
#include <list>
#include <getopt.h>
#include <sys/time.h>
#include <fts.h>

#include "Endpoint.hpp"
/* for locking */
@@ -1677,51 +1675,141 @@ OSC_HANDLER( new )
return 0;
}

int
fts_comparer_to_process_files_before_dirs( const FTSENT ** first, const FTSENT ** second )
{
/*
The argument compar() specifies a user-defined function which may
be used to order the traversal of the hierarchy. It takes two
pointers to pointers to FTSENT structures as arguments and should
return a negative value, zero, or a positive value to indicate if
the file referenced by its first argument comes before, in any
order with respect to, or after, the file referenced by its
second argument. The fts_accpath, fts_path, and fts_pathlen
fields of the FTSENT structures may never be used in this
comparison. If the fts_info field is set to FTS_NS or FTS_NSOK,
the fts_statp field may not either. If the compar() argument is
NULL, the directory traversal order is in the order listed in
path_argv for the root paths, and in the order listed in the
directory for everything else.
*/

if ( (*first)->fts_info & FTS_F )
return (-1); //first
else if ( (*second)->fts_info & FTS_F )
return (1); //last
else
return strcmp((*first)->fts_name, (*second)->fts_name);
//return (0); //doesn't matter
}


static lo_address list_response_address;

int
list_file ( const char *fpath, const struct stat *sb, int tflag )
OSC_HANDLER( list )
{
if ( tflag == FTW_F )
{
char *s;
s = strdup( fpath );
if ( ! strcmp( "session.nsm", basename( s ) ) )
{
free( s );
s = strdup( fpath );
//Parse the session_root recursively for session.nsm files and send names with /nsm/server/list
//Sessions can be structured with sub-directories.
//The file session.nsm marks a real session and is a 'leaf' of the session tree.
//No other sessions are allowed below a dir containing session.nsm .

s = dirname( s );
GUIMSG( "Listing sessions" );
list_response_address = lo_message_get_source( msg );

memmove( s, s + strlen( session_root ) + 1, (strlen( s ) - strlen( session_root )) + 1);
//Use fts to walk the session_root
/* An array of paths to traverse. Each path must be null
* terminated and the list must end with a NULL pointer. */
char *paths[] = { session_root, NULL };

osc_server->send( list_response_address, "/reply", "/nsm/server/list", s );
/* 2nd parameter: An options parameter. Must include either
FTS_PHYSICAL or FTS_LOGICAL---they change how symbolic links
are handled.

free( s );
}
else
free( s );
}
Last parameter is a comparator which you can optionally provide
to change the traversal of the filesystem hierarchy.

return 0;
}
Our comparator processes files before directories, so we can depend on that
to remember if we are already in a session-dir.
*/

OSC_HANDLER( list )
{
GUIMSG( "Listing sessions" );
FTS *ftsp = fts_open(paths, FTS_LOGICAL, fts_comparer_to_process_files_before_dirs);
if(ftsp == NULL)
{
FATAL( "fts_open" );
exit(EXIT_FAILURE);
}

list_response_address = lo_message_get_source( msg );
FTSENT * currentSession = NULL;
while( 1 ) // call fts_read() enough times to get each file
{
FTSENT *ent = fts_read(ftsp); // get next entry (could be file or directory).
if( ent == NULL )
{
if( errno == 0 )
break; // No more items, bail out of while loop
else
{
// fts_read() had an error.
FATAL( "fts_read" );
exit(EXIT_FAILURE);
}
}

ftw( session_root, list_file, 20 );
// Handle Types of Files

// osc_server->send( lo_message_get_source( msg ), path, ERR_OK, "Done." );
// Given a "entry", determine if it is a file or directory
if( ent->fts_info & FTS_D ) // We are entering into a directory
{
//printf( "Enter dir: %s\n", ent->fts_path );
if ( currentSession != NULL )
{
//printf( "already found current session.nsm: %s . Waiting to leave dir. Ignoring %s\n", currentSession->fts_name, ent->fts_path );

// Setup that no descendants of this file are visited.
int err = fts_set( ftsp, ent, FTS_SKIP );
if ( err != 0 )
{
FATAL( "fts_set" );
exit(EXIT_FAILURE);
}
}
}
else if( ent->fts_info & FTS_DP ) // We are exiting a directory
{
//printf( "Exit dir: %s\n", ent->fts_path );
if ( ent == currentSession )
{
//printf( "Exit current session dir: %s\n", ent->fts_path );
currentSession = NULL;
}
}
else if( ent->fts_info & FTS_F ) // The entry is a file.
{
//printf( "File: %s\n", ent->fts_path );
if ( ! strcmp( "session.nsm", basename( ent->fts_path ) ) )
{
//Convert path to session name:
char *s;
s = strdup( ent->fts_path );
s = dirname( s );
memmove( s, s + strlen( session_root ) + 1, (strlen( s ) - strlen( session_root )) + 1);
osc_server->send( list_response_address, "/reply", "/nsm/server/list", s );
free( s );
currentSession = ent->fts_parent; //save the directory entry. not the session.nsm entry.
}
}
}

// close fts and check for error closing.
if(fts_close(ftsp) == -1)
FATAL( "fts_close" );

// As marker that all sessions were sent reply with an empty string, which is impossible to conflict with a session name
osc_server->send( list_response_address, "/reply", "/nsm/server/list", "" );

return 0;
}


OSC_HANDLER( open )
{
lo_address sender_addr;


Loading…
Cancel
Save