📄 vfs-file-task.c
字号:
call_state_callback( task, VFS_FILE_TASK_ERROR ); } g_free( dest_file );}static voidvfs_file_task_delete( char* src_file, VFSFileTask* task ){ GDir * dir; gchar* file_name; gchar* sub_src_file; struct stat file_stat; int result; task->current_file = src_file; if ( should_abort( task ) ) return ; if ( lstat( src_file, &file_stat ) == -1 ) { task->error = errno; call_state_callback( task, VFS_FILE_TASK_ERROR ); return ; /* Error occurred */ } task->current_file = src_file; call_progress_callback( task ); if ( S_ISDIR( file_stat.st_mode ) ) { dir = g_dir_open( src_file, 0, NULL ); while ( (file_name = g_dir_read_name( dir )) ) { if ( should_abort( task ) ) break; sub_src_file = g_build_filename( src_file, file_name, NULL ); vfs_file_task_delete( sub_src_file, task ); g_free( sub_src_file ); } g_dir_close( dir ); if ( should_abort( task ) ) return ; result = rmdir( src_file ); if ( result != 0 ) { task->error = errno; call_state_callback( task, VFS_FILE_TASK_ERROR ); return ; } task->progress += file_stat.st_size; call_progress_callback( task ); } else { result = unlink( src_file ); if ( result != 0 ) { task->error = errno; call_state_callback( task, VFS_FILE_TASK_ERROR ); return ; } task->progress += file_stat.st_size; call_progress_callback( task ); }}static voidvfs_file_task_link( char* src_file, VFSFileTask* task ){ struct stat src_stat, dest_stat; int result; gchar* dest_file; gchar* file_name = g_path_get_basename( src_file ); if ( should_abort( task ) ) return ; file_name = g_path_get_basename( src_file ); dest_file = g_build_filename( task->dest_dir, file_name, NULL ); g_free( file_name ); call_progress_callback( task ); if ( stat( src_file, &src_stat ) == -1 ) { task->error = errno; call_state_callback( task, VFS_FILE_TASK_ERROR ); if ( should_abort( task ) ) return ; } /* FIXME: Check overwrite!! */ result = symlink( src_file, dest_file ); g_free( dest_file ); if ( result ) { task->error = errno; call_state_callback( task, VFS_FILE_TASK_ERROR ); if ( should_abort( task ) ) return ; } task->progress += src_stat.st_size; call_progress_callback( task );}static voidvfs_file_task_chown_chmod( char* src_file, VFSFileTask* task ){ struct stat src_stat; int i; GDir* dir; gchar* sub_src_file; gchar* file_name; mode_t new_mode; int result; if( should_abort( task ) ) return ; task->current_file = src_file; /* g_debug("chmod_chown: %s\n", src_file); */ call_progress_callback( task ); if ( lstat( src_file, &src_stat ) == 0 ) { /* chown */ if ( task->uid != -1 || task->gid != -1 ) { result = chown( src_file, task->uid, task->gid ); if ( result != 0 ) { task->error = errno; call_state_callback( task, VFS_FILE_TASK_ERROR ); if ( should_abort( task ) ) return ; } } /* chmod */ if ( task->chmod_actions ) { new_mode = src_stat.st_mode; for ( i = 0; i < N_CHMOD_ACTIONS; ++i ) { if ( task->chmod_actions[ i ] == 2 ) /* Don't change */ continue; if ( task->chmod_actions[ i ] == 0 ) /* Remove this bit */ new_mode &= ~chmod_flags[ i ]; else /* Add this bit */ new_mode |= chmod_flags[ i ]; } if ( new_mode != src_stat.st_mode ) { result = chmod( src_file, new_mode ); if ( result != 0 ) { task->error = errno; call_state_callback( task, VFS_FILE_TASK_ERROR ); if ( should_abort( task ) ) return ; } } } task->progress += src_stat.st_size; call_progress_callback( task ); if ( S_ISDIR( src_stat.st_mode ) && task->recursive ) { if ( (dir = g_dir_open( src_file, 0, NULL )) ) { while ( (file_name = g_dir_read_name( dir )) ) { if ( should_abort( task ) ) break; sub_src_file = g_build_filename( src_file, file_name, NULL ); vfs_file_task_chown_chmod( sub_src_file, task ); g_free( sub_src_file ); } g_dir_close( dir ); } else { task->error = errno; call_state_callback( task, VFS_FILE_TASK_ERROR ); if ( should_abort( task ) ) return ; } } }}static gpointer vfs_file_task_thread ( VFSFileTask* task ){ GList * l; struct stat file_stat; dev_t dest_dev; char* src_path; gboolean cancelled = FALSE; GFunc funcs[] = {( GFunc ) vfs_file_task_move, ( GFunc ) vfs_file_task_copy, ( GFunc ) vfs_file_task_delete, ( GFunc ) vfs_file_task_link, ( GFunc ) vfs_file_task_chown_chmod}; if ( task->type < VFS_FILE_TASK_MOVE || task->type >= VFS_FILE_TASK_LAST ) goto _exit_thread; task->state = VFS_FILE_TASK_RUNNING; task->current_file = ( char* ) task->src_paths->data; task->total_size = 0; call_progress_callback( task ); /* Calculate total size of all files */ if ( task->recursive ) { for ( l = task->src_paths; l; l = l->next ) { if( task->dest_dir && g_str_has_prefix( task->dest_dir, (char*)l->data ) ) { /* FIXME: This has serious problems */ /* Check if source file is contained in destination dir */ /* The src file is already in dest dir */ if( lstat( (char*)l->data, &file_stat ) == 0 && S_ISDIR(file_stat.st_mode) ) { /* It's a dir */ if ( task->state_cb ) { char* err; char* disp_src; char* disp_dest; disp_src = g_filename_display_name( (char*)l->data ); disp_dest = g_filename_display_name( task->dest_dir ); err = g_strdup_printf( _("Destination directory \"%1$s\" is contained in source \"%2$s\""), disp_dest, disp_src ); if ( task->state_cb( task, VFS_FILE_TASK_ERROR, err, task->state_cb_data ) ) task->state = VFS_FILE_TASK_RUNNING; else task->state = VFS_FILE_TASK_ABORTED; g_free( disp_src ); g_free( disp_dest ); g_free( err ); } else task->state = VFS_FILE_TASK_ABORTED; if ( should_abort( task ) ) goto _exit_thread; } } get_total_size_of_dir( task, ( char* ) l->data, &task->total_size ); } } else { if ( task->type != VFS_FILE_TASK_CHMOD_CHOWN ) { if ( task->dest_dir && lstat( task->dest_dir, &file_stat ) < 0 ) { task->error = errno; call_state_callback( task, VFS_FILE_TASK_ERROR ); if ( should_abort( task ) ) goto _exit_thread; } dest_dev = file_stat.st_dev; } for ( l = task->src_paths; l; l = l->next ) { if ( lstat( ( char* ) l->data, &file_stat ) == -1 ) { task->error = errno; call_state_callback( task, VFS_FILE_TASK_ERROR ); if ( should_abort( task ) ) goto _exit_thread; } if ( S_ISLNK( file_stat.st_mode ) ) /* Don't do deep copy for symlinks */ task->recursive = FALSE; else if ( task->type == VFS_FILE_TASK_MOVE ) task->recursive = ( file_stat.st_dev != dest_dev ); if ( task->recursive ) { get_total_size_of_dir( task, ( char* ) l->data, &task->total_size ); } else { task->total_size += file_stat.st_size; } } } g_list_foreach( task->src_paths, funcs[ task->type ], task );_exit_thread: if ( task->state_cb ) call_state_callback( task, VFS_FILE_TASK_FINISH ); else { /* FIXME: Will this cause any problem? */ task->thread = NULL; vfs_file_task_free( task ); } return NULL;}/** source_files sould be a newly allocated list, and it will be* freed after file operation has been completed*/VFSFileTask* vfs_task_new ( VFSFileTaskType type, GList* src_files, const char* dest_dir ){ VFSFileTask * task; task = g_slice_new0( VFSFileTask ); task->type = type; task->src_paths = src_files; if ( dest_dir ) task->dest_dir = g_strdup( dest_dir ); if ( task->type == VFS_FILE_TASK_COPY || task->type == VFS_FILE_TASK_DELETE ) task->recursive = TRUE; return task;}/* Set some actions for chmod, this array will be copied* and stored in VFSFileTask */void vfs_file_task_set_chmod( VFSFileTask* task, guchar* chmod_actions ){ task->chmod_actions = g_slice_alloc( sizeof( guchar ) * N_CHMOD_ACTIONS ); memcpy( ( void* ) task->chmod_actions, ( void* ) chmod_actions, sizeof( guchar ) * N_CHMOD_ACTIONS );}void vfs_file_task_set_chown( VFSFileTask* task, uid_t uid, gid_t gid ){ task->uid = uid; task->gid = gid;}void vfs_file_task_run ( VFSFileTask* task ){ task->thread = g_thread_create( ( GThreadFunc ) vfs_file_task_thread, task, TRUE, NULL );}void vfs_file_task_try_abort ( VFSFileTask* task ){ task->state = VFS_FILE_TASK_QUERY_ABORT;}void vfs_file_task_abort ( VFSFileTask* task ){ task->state = VFS_FILE_TASK_ABORTED; /* Called from another thread */ if ( g_thread_self() != task->thread ) { g_thread_join( task->thread ); task->thread = NULL; }}void vfs_file_task_free ( VFSFileTask* task ){ if ( task->src_paths ) { g_list_foreach( task->src_paths, ( GFunc ) g_free, NULL ); g_list_free( task->src_paths ); } g_free( task->dest_dir ); if ( task->chmod_actions ) g_slice_free1( sizeof( guchar ) * N_CHMOD_ACTIONS, task->chmod_actions ); g_slice_free( VFSFileTask, task );}/** void get_total_size_of_dir( const char* path, off_t* size )* Recursively count total size of all files in the specified directory.* If the path specified is a file, the size of the file is directly returned.* cancel is used to cancel the operation. This function will check the value* pointed by cancel in every iteration. If cancel is set to TRUE, the* calculation is cancelled.* NOTE: *size should be set to zero before calling this function.*/void get_total_size_of_dir( VFSFileTask* task, const char* path, off_t* size ){ GDir * dir; const char* name; char* full_path; struct stat file_stat; if ( should_abort( task ) ) return; lstat( path, &file_stat ); *size += file_stat.st_size; if ( S_ISLNK( file_stat.st_mode ) ) /* Don't follow symlinks */ return ; dir = g_dir_open( path, 0, NULL ); if ( dir ) { while ( (name = g_dir_read_name( dir )) ) { if ( should_abort( task ) ) break; full_path = g_build_filename( path, name, NULL ); lstat( full_path, &file_stat ); if ( S_ISDIR( file_stat.st_mode ) ) { get_total_size_of_dir( task, full_path, size ); } else { *size += file_stat.st_size; } g_free( full_path ); } g_dir_close( dir ); }}void vfs_file_task_set_recursive( VFSFileTask* task, gboolean recursive ){ task->recursive = recursive;}void vfs_file_task_set_overwrite_mode( VFSFileTask* task, VFSFileTaskOverwriteMode mode ){ task->overwrite_mode = mode;}void vfs_file_task_set_progress_callback( VFSFileTask* task, VFSFileTaskProgressCallback cb, gpointer user_data ){ task->progress_cb = cb; task->progress_cb_data = user_data;}void vfs_file_task_set_state_callback( VFSFileTask* task, VFSFileTaskStateCallback cb, gpointer user_data ){ task->state_cb = cb; task->state_cb_data = user_data;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -