Permalink
Browse files

dir change monitor truly canonicalize paths

If two equivalent symlink-containing paths were monitored and one was removed
they were both removed (by wd number).  To prevent this the path is now
canonicalized before being added to the monitor.
  • Loading branch information...
1 parent 1c6fea5 commit 1be8be03483d47b7389061fe9f8063efc6621aa9 @IgnorantGuru committed Feb 22, 2013
Showing with 46 additions and 15 deletions.
  1. +1 −0 ChangeLog
  2. +10 −2 src/vfs/vfs-dir.c
  3. +35 −13 src/vfs/vfs-file-monitor.c
View
@@ -15,6 +15,7 @@
Jui contributed to Czech translation
fix spacefm -p 1 nospec opens wrong panel
always present window on create
+ dir change monitor truly canonicalize paths
0.8.6 2013-02-13:
fix cannot create directory or file on CentOS #253
update russian translation
View
@@ -206,7 +206,7 @@ void vfs_dir_init( VFSDir* dir )
void vfs_dir_finalize( GObject *obj )
{
VFSDir * dir = VFS_DIR( obj );
-
+//printf("vfs_dir_finalize %s\n", dir->path );
do{}
while( g_source_remove_by_user_data( dir ) );
@@ -390,7 +390,15 @@ void vfs_dir_emit_file_changed( VFSDir* dir, const char* file_name,
if ( !force && dir->avoid_changes )
return;
-
+
+/* Test not needed because file won't be found in list?
+ if ( G_UNLIKELY( 0 == strcmp(file_name, dir->path) ) )
+ {
+ // Special Case: The directory itself was changed
+ return;
+ }
+*/
+
g_mutex_lock( dir->mutex );
l = vfs_dir_find_file( dir, file_name, file );
@@ -147,26 +147,42 @@ VFSFileMonitor* vfs_file_monitor_add( char* path,
VFSFileMonitor * monitor;
VFSFileMonitorCallbackEntry cb_ent;
struct stat file_stat; // skip stat64
- gchar* real_path = NULL;
+ char resolved_path[PATH_MAX];
+ char* real_path;
//printf( "vfs_file_monitor_add %s\n", path );
if ( ! monitor_hash )
return NULL;
- monitor = ( VFSFileMonitor* ) g_hash_table_lookup ( monitor_hash, path );
+ // Since gamin, FAM and inotify don't follow symlinks, need to get real path
+ if ( strlen( path ) > PATH_MAX - 1 )
+ {
+ g_warning ( "PATH_MAX exceeded on %s", path );
+ real_path = path; //fallback
+ }
+ else if ( realpath( path, resolved_path ) == NULL )
+ {
+ g_warning ( "realpath failed on %s", path );
+ real_path = path; //fallback
+ }
+ else
+ real_path = resolved_path;
+
+ monitor = ( VFSFileMonitor* ) g_hash_table_lookup ( monitor_hash, real_path );
if ( ! monitor )
{
monitor = g_slice_new0( VFSFileMonitor );
- monitor->path = g_strdup( path );
+ monitor->path = g_strdup( real_path );
monitor->callbacks = g_array_new ( FALSE, FALSE, sizeof( VFSFileMonitorCallbackEntry ) );
g_hash_table_insert ( monitor_hash,
monitor->path,
monitor );
- /* NOTE: Since gamin, FAM and inotify don't follow symlinks,
- we need to do some special processing here. */
+ /* OLD METHOD - removes wrong dir due to symlinks
+ // NOTE: Since gamin, FAM and inotify don't follow symlinks,
+ we need to do some special processing here.
if ( lstat( path, &file_stat ) == 0 )
{
const char* link_file = path;
@@ -182,36 +198,40 @@ VFSFileMonitor* vfs_file_monitor_add( char* path,
link_file = real_path;
}
}
+ */
#ifdef USE_INOTIFY /* Linux inotify */
- monitor->wd = inotify_add_watch ( inotify_fd, real_path ? real_path : path,
- IN_MODIFY | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE | IN_MOVE_SELF | IN_UNMOUNT | IN_ATTRIB);
+ monitor->wd = inotify_add_watch ( inotify_fd, real_path,
+ IN_MODIFY | IN_CREATE | IN_DELETE |
+ IN_DELETE_SELF | IN_MOVE |
+ IN_MOVE_SELF | IN_UNMOUNT | IN_ATTRIB );
if ( monitor->wd < 0 )
{
- g_warning ( "Failed to add monitor on '%s': %s",
- path,
+ g_warning ( "Failed to add monitor on '%s' ('%s'): %s",
+ real_path, path,
g_strerror ( errno ) );
return NULL;
}
+//printf("vfs_file_monitor_add %s (%s) %d\n", real_path, path, monitor->wd );
+
#else /* Use FAM|gamin */
//MOD see NOTE1 in vfs-mime-type.c - what happens here if path doesn't exist?
// inotify returns NULL - does fam?
if ( is_dir )
{
FAMMonitorDirectory( &fam,
- real_path ? real_path : path,
+ real_path,
&monitor->request,
monitor );
}
else
{
FAMMonitorFile( &fam,
- real_path ? real_path : path,
+ real_path,
&monitor->request,
monitor );
}
#endif
- g_free( real_path );
}
if( G_LIKELY(monitor) )
@@ -252,6 +272,7 @@ void vfs_file_monitor_remove( VFSFileMonitor * fm,
if ( fm && g_atomic_int_dec_and_test( &fm->n_ref ) ) //MOD added "fm &&"
{
#ifdef USE_INOTIFY /* Linux inotify */
+//printf( "vfs_file_monitor_remove %d\n", fm->wd );
inotify_rm_watch ( inotify_fd, fm->wd );
#else /* Use FAM|gamin */
FAMCancelMonitor( &fam, &fm->request );
@@ -412,7 +433,8 @@ static gboolean on_fam_event( GIOChannel * channel,
while ( i < len )
{
struct inotify_event * ievent = ( struct inotify_event * ) & buf [ i ];
- /* FIXME: 2 different paths can have the same wd because of link */
+ /* FIXME: 2 different paths can have the same wd because of link
+ * This was fixed in spacefm 0.8.7 ?? */
monitor = ( VFSFileMonitor* ) g_hash_table_find(
monitor_hash,
find_monitor,

0 comments on commit 1be8be0

Please sign in to comment.