⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vfs-file-task.c

📁 台湾人开发的Linux下的文件管理器
💻 C
📖 第 1 页 / 共 2 页
字号:
/**  C Implementation: vfs-file-task** Description:*** Author: Hong Jen Yee (PCMan) <pcman.tw (AT) gmail.com>, (C) 2005** Copyright: See COPYING file that comes with this distribution**/#ifdef HAVE_CONFIG_H#  include <config.h>#endif#include "vfs-file-task.h"#include <unistd.h>#include <fcntl.h>#include <utime.h>#include <sys/types.h>#include <sys/stat.h>#include <glib.h>#include "glib-mem.h"#include <glib/gi18n.h>#include <stdio.h>#include <string.h>#include <errno.h>const mode_t chmod_flags[] =    {        S_IRUSR, S_IWUSR, S_IXUSR,        S_IRGRP, S_IWGRP, S_IXGRP,        S_IROTH, S_IWOTH, S_IXOTH,        S_ISUID, S_ISGID, S_ISVTX    };/** 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.*/static void get_total_size_of_dir( VFSFileTask* task,                                   const char* path,                                   off_t* size );static gbooleancall_progress_callback( VFSFileTask* task ){    /* FIXME: This has some impact on performance */    gdouble percent = ( ( gdouble ) task->progress ) / task->total_size;    int ipercent = ( int ) ( percent * 100 );    if ( ipercent != task->percent )        task->percent = ipercent;    if ( task->progress_cb )    {        task->progress_cb( task, task->percent,                           task->current_file,                           NULL,                           task->progress_cb_data );    }    return FALSE;}static void call_state_callback( VFSFileTask* task,                          VFSFileTaskState state ){    task->state = state;    if ( task->state_cb )    {        if ( ! task->state_cb( task, state, NULL, task->state_cb_data ) )            task->state = VFS_FILE_TASK_ABORTED;        else            task->state = VFS_FILE_TASK_RUNNING;    }}static gboolean should_abort( VFSFileTask* task ){    if ( task->state == VFS_FILE_TASK_QUERY_ABORT )    {        call_state_callback( task, VFS_FILE_TASK_QUERY_ABORT );        if ( task->state == VFS_FILE_TASK_ABORTED )            return TRUE;    }    return ( task->state == VFS_FILE_TASK_ABORTED );}/** Check if the destination file exists.* If the dest_file exists, let the user choose a new destination,* skip this file, overwrite existing file, or cancel all file operation.* The returned string is the new destination file choosed by the user*/static gboolean check_overwrite( VFSFileTask* task,                          const gchar* dest_file,                          gboolean* dest_exists,                          char** new_dest_file ){    char * new_dest;    new_dest = *new_dest_file = NULL;    struct stat dest_stat;    if ( task->overwrite_mode == VFS_FILE_TASK_OVERWRITE_ALL )    {        *dest_exists = !lstat( dest_file, &dest_stat );        return TRUE;    }    if ( task->overwrite_mode == VFS_FILE_TASK_SKIP_ALL )    {        *dest_exists = !lstat( dest_file, &dest_stat );        return FALSE;    }    *dest_exists = FALSE;    if ( task->state_cb )    {        while ( lstat( dest_file, &dest_stat ) != -1 )        {            *dest_exists = TRUE;            /* destination file exists */            task->state = VFS_FILE_TASK_QUERY_OVERWRITE;            if ( ! task->state_cb( task, VFS_FILE_TASK_QUERY_OVERWRITE,                                   &new_dest, task->state_cb_data ) )            {                task->state = VFS_FILE_TASK_ABORTED;            }            else            {                task->state = VFS_FILE_TASK_RUNNING;            }            if ( should_abort( task ) )                return FALSE;            if( task->overwrite_mode != VFS_FILE_TASK_RENAME )            {                g_free( new_dest );                *new_dest_file = NULL;                if( task->overwrite_mode == VFS_FILE_TASK_OVERWRITE ||                    task->overwrite_mode == VFS_FILE_TASK_OVERWRITE_ALL )                {                    return TRUE;                }                else                    return FALSE;            }            if ( new_dest )                dest_file = new_dest;        }        *dest_exists = FALSE;        *new_dest_file = new_dest;    }    return ! should_abort( task );}static voidvfs_file_task_do_copy( VFSFileTask* task,                       const char* src_file,                       const char* dest_file ){    GDir * dir;    gchar* file_name;    gchar* sub_src_file;    gchar* sub_dest_file;    struct stat file_stat;    char buffer[ 4096 ];    int rfd;    int wfd;    ssize_t rsize;    char* new_dest_file = NULL;    gboolean dest_exists;    int overwrite_mode;    int result;    if ( should_abort( task ) )        return ;    if ( lstat( src_file, &file_stat ) == -1 )    {        /* Error occurred */        call_state_callback( task, VFS_FILE_TASK_ERROR );        if ( should_abort( task ) )            return ;    }    task->current_file = src_file;    task->current_dest = dest_file;    call_progress_callback( task );    result = 0;    if ( S_ISDIR( file_stat.st_mode ) )    {        if ( ! check_overwrite( task, dest_file,                                &dest_exists, &new_dest_file ) )            goto _return_;        if ( new_dest_file )            task->current_dest = dest_file = new_dest_file;        if ( ! dest_exists )            result = mkdir( dest_file, file_stat.st_mode | 0700 );        if ( result == 0 )        {            struct utimbuf times;            task->progress += file_stat.st_size;            call_progress_callback( task );            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 );                sub_dest_file = g_build_filename( dest_file, file_name, NULL );                vfs_file_task_do_copy( task, sub_src_file, sub_dest_file );                g_free( sub_dest_file );                g_free( sub_src_file );            }            g_dir_close( dir );            chmod( dest_file, file_stat.st_mode );            times.actime = file_stat.st_atime;            times.modtime = file_stat.st_mtime;            utime( dest_file, &times );            /* Move files to different device: Need to delete source files */            if ( task->type == VFS_FILE_TASK_MOVE && !should_abort( task ) )            {                if ( (result = rmdir( src_file )) )                {                    task->error = errno;                    call_state_callback( task, VFS_FILE_TASK_ERROR );                    if ( should_abort( task ) )                        goto _return_;                }            }        }        else        {  /* result != 0, error occurred */            task->error = errno;            call_state_callback( task, VFS_FILE_TASK_ERROR );        }    }    else if ( S_ISLNK( file_stat.st_mode ) )    {        if ( ( rfd = readlink( src_file, buffer, sizeof( buffer ) ) ) > 0 )        {            if ( ! check_overwrite( task, dest_file,                                    &dest_exists, &new_dest_file ) )                goto _return_;            if ( new_dest_file )                task->current_dest = dest_file = new_dest_file;            if ( ( wfd = symlink( buffer, dest_file ) ) == 0 )            {                chmod( dest_file, file_stat.st_mode );                /* Move files to different device: Need to delete source files */                if ( task->type == VFS_FILE_TASK_MOVE )                {                    result = unlink( src_file );                    if ( result )                    {                        task->error = errno;                        call_state_callback( task, VFS_FILE_TASK_ERROR );                    }                }                task->progress += file_stat.st_size;                call_progress_callback( task );            }            else            {                task->error = errno;                call_state_callback( task, VFS_FILE_TASK_ERROR );            }        }        else        {            task->error = errno;            call_state_callback( task, VFS_FILE_TASK_ERROR );        }    }    else    {        if ( ( rfd = open( src_file, O_RDONLY ) ) >= 0 )        {            if ( ! check_overwrite( task, dest_file,                                    &dest_exists, &new_dest_file ) )                goto _return_;            if ( new_dest_file )                task->current_dest = dest_file = new_dest_file;            if ( ( wfd = creat( dest_file,                                 file_stat.st_mode | S_IWUSR ) ) >= 0 )            {                struct utimbuf times;                while ( ( rsize = read( rfd, buffer, sizeof( buffer ) ) ) > 0 )                {                    if ( should_abort( task ) )                        break;                    if ( write( wfd, buffer, rsize ) > 0 )                        task->progress += rsize;                    else                    {                        task->error = errno;                        call_state_callback( task, VFS_FILE_TASK_ERROR );                        close( wfd );                    }                    call_progress_callback( task );                }                close( wfd );                chmod( dest_file, file_stat.st_mode );                times.actime = file_stat.st_atime;                times.modtime = file_stat.st_mtime;                utime( dest_file, &times );                /* Move files to different device: Need to delete source files */                if ( task->type == VFS_FILE_TASK_MOVE && !should_abort( task ) )                {                    result = unlink( src_file );                    if ( result )                    {                        task->error = errno;                        call_state_callback( task, VFS_FILE_TASK_ERROR );                    }                }            }            else            {                task->error = errno;                call_state_callback( task, VFS_FILE_TASK_ERROR );            }            close( rfd );        }        else        {            task->error = errno;            call_state_callback( task, VFS_FILE_TASK_ERROR );        }    }_return_:    g_free( new_dest_file );}static voidvfs_file_task_copy( char* src_file, VFSFileTask* task ){    gchar * file_name;    gchar* dest_file;    call_progress_callback( task );    file_name = g_path_get_basename( src_file );    dest_file = g_build_filename( task->dest_dir, file_name, NULL );    g_free( file_name );    vfs_file_task_do_copy( task, src_file, dest_file );    g_free( dest_file );}static voidvfs_file_task_do_move ( VFSFileTask* task,                        const char* src_file,                        const char* dest_file ){    GDir * dir;    gchar* file_name;    gchar* new_dest_file = NULL;    gboolean dest_exists;    gchar* sub_src_file;    gchar* sub_dest_file;    struct stat file_stat;    int overwrite_mode, result;    if ( should_abort( task ) )        return ;    /* g_debug( "move \"%s\" to \"%s\"\n", src_file, dest_file ); */    if ( lstat( src_file, &file_stat ) == -1 )    {        task->error = errno;    /* Error occurred */        call_state_callback( task, VFS_FILE_TASK_ERROR );        if ( should_abort( task ) )            return ;    }    task->current_file = src_file;    task->current_dest = dest_file;    if ( should_abort( task ) )        return ;    call_progress_callback( task );    if ( ! check_overwrite( task, dest_file,           &dest_exists, &new_dest_file ) )        return ;    if ( new_dest_file )        task->current_dest = dest_file = new_dest_file;    result = rename( src_file, dest_file );    if ( result != 0 )    {        task->error = errno;        call_state_callback( task, VFS_FILE_TASK_ERROR );        if ( should_abort( task ) )        {            g_free( new_dest_file );            return ;        }    }    else        chmod( dest_file, file_stat.st_mode );    task->progress += file_stat.st_size;    call_progress_callback( task );    g_free( new_dest_file );}static voidvfs_file_task_move( char* src_file, VFSFileTask* task ){    struct stat src_stat;    struct stat dest_stat;    gchar* file_name;    gchar* dest_file;    if ( should_abort( task ) )        return ;    task->current_file = src_file;    file_name = g_path_get_basename( src_file );    dest_file = g_build_filename( task->dest_dir, file_name, NULL );    g_free( file_name );    if ( lstat( src_file, &src_stat ) == 0            && lstat( task->dest_dir, &dest_stat ) == 0 )    {        /* Not on the same device */        if ( src_stat.st_dev != dest_stat.st_dev )        {            /* g_print("not on the same dev: %s\n", src_file); */            vfs_file_task_do_copy( task, src_file, dest_file );        }        else        {            /* g_print("on the same dev: %s\n", src_file); */            vfs_file_task_do_move( task, src_file, dest_file );        }    }    else    {        task->error = errno;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -