本文主要讲解 dentry_move dentry_copy dentry_trash dentry_delete 相关机制、联系、区别.
dentry源码:https://github.com/linuxdeepin/dde/tree/develop/lib/dentry
测试代码源码:https://github.com/linuxdeepin/dde/tree/desktop_test/app/desktop/test
核心点:
move trash 不需要遍历,实质只是将节点inode 从src进行链接到dest
copy delete 就需要遍历了,且遍历方法不同,及 post_hook pre_hook
核心测试代码:
gpointer* _gp = g_object_ref(g_ptr_array_index(gfileDirectory,0)); ArrayContainer fs = {&_gp,1}; GFile* dest = g_file_new_for_uri("file:///home/ycl"); Test({ g_message("move start"); dentry_move(fs,dest,FALSE); g_message("move end"); g_message("0copy start"); GFile* _dest0 = g_file_new_for_uri("file:///home/ycl/dde/build/"); GFile* _src0 = g_file_new_for_uri("file:///home/ycl/test_files"); ArrayContainer _fs0; _fs0.data=&_src0; _fs0.num = 1; dentry_copy(_fs0,_dest0); g_object_unref(_dest0); ArrayContainer_free0(_fs0); g_message("0copy end"); g_message("1trash start"); GFile* _src1 = g_file_new_for_uri("file:///home/ycl/test_files"); ArrayContainer _fs1; _fs1.data=&_src1; _fs1.num = 1; dentry_trash(_fs1); ArrayContainer_free0(_fs1); g_message("1trash end"); g_message("2copy start"); GFile* _src2 = g_file_new_for_uri("file:///home/ycl/dde/build/test_files"); GFile* _dest2 = g_file_new_for_uri("file:///home/ycl/"); ArrayContainer _fs2; _fs2.data=&_src2; _fs2.num = 1; dentry_copy(_fs2,_dest2); g_object_unref(_dest2); ArrayContainer_free0(_fs2); g_message("2copy end"); g_message("3delete start"); GFile* _src3 = g_file_new_for_uri("file:///home/ycl/test_files"); ArrayContainer _fs3; _fs3.data=&_src3; _fs3.num = 1; dentry_delete_files(_fs3,FALSE); ArrayContainer_free0(_fs3); g_message("3delete end"); },"dentry_move"); ArrayContainer_free0(fs); g_object_unref(dest);
一、dentry_move
extern gboolean dentry_move(ArrayContainer fs, GFile* dest, gboolean prompt);
move 调试信息:(move的是文件夹)
------先直接move的整个文件夹(不是copy),然后delete src源
问:为何调试信息中fileops_delete 不是先delete 内部文件再delete dest的文件夹??
** Message: move start ** (desktop:20038): DEBUG: fileops_move: Begin moving files ** (desktop:20038): DEBUG: fileops_move: file 0: file:///home/ycl/dde/build/test_files to dest: file:///home/ycl ** (desktop:20038): DEBUG: begin _move_files_async ** (desktop:20038): DEBUG: _move_files_async: move file:///home/ycl/dde/build/test_files to file:///home/ycl/test_files ** (desktop:20038): DEBUG: traverse_directory: chdir to : file:///home/ycl/dde/build/test_files ** (desktop:20038): DEBUG: traverse_directory: come out: file:///home/ycl/dde/build/test_files ** (desktop:20038): DEBUG: fileops_delete: Begin deleting files ** (desktop:20038): DEBUG: fileops_delete: file 0: file:///home/ycl/dde/build/test_files ** (desktop:20038): WARNING **: traverse_directory 1: 没有那个文件或目录 ** (desktop:20038): DEBUG: fileops_delete: End deleting files ** (desktop:20038): DEBUG: fileops_move: End moving files ** Message: move end
解释上一个问题:
// 注释掉的部分,是为了解决当move的dest中已有src的文件夹,甚至是文件夹中的内容都有重复的这个bug。 ---错误处理
//retval &= _move_files_async (src, data); //traverse_directory (dir, _move_files_async, _dummy_func, move_dest_gfile); retval &= traverse_directory (src, _move_files_async, _dummy_func, data); if (retval) fileops_delete (&src, 1);//ensure original file is removed.
故先需要进行遍历,遍历的目的不是为了删除src的文件夹,而是为了判断dest中是否需要错误处理(是否有共同文件夹和文件)
既然目的明确了,那么在traverse_directory中错误处理完成后,直接删除掉整个src的文件夹就足够了。故fileops_delete (&src, 1)的num为1(既不论是文件夹还是单独文件,直接delete掉就行,不再让delete进行遍历。)
gboolean dentry_move(ArrayContainer fs, GFile* dest, gboolean prompt)
当dest中已存在要复制的文件时,
prompt=FALSE :不会copy,也不会delete.
prompt=TRUE;提示是否覆盖。程序根据response来决定后续操作
代码位置:
fileops.c中的_move_files_async (GFile* src, gpointer data)中的:
。。。。。。。。。。 g_file_move (src, dest, G_FILE_COPY_NOFOLLOW_SYMLINKS, _move_cancellable, NULL, NULL, &error); GFileType type = g_file_query_file_type (src, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL); if (error != NULL) { // g_cancellable_cancel (_move_cancellable); g_warning ("_move_files_async: %s", error->message); //TEST: if (g_prompt == TRUE) { 。。。。。。。。。。。。 if (response != NULL && response->apply_to_all) g_move_response = fileops_response_dup (response); } if(response != NULL) { switch (response->response_id) { case GTK_RESPONSE_CANCEL:
选择取消时,打印信息如下:
** Message: move start ** (desktop:14158): DEBUG: fileops_move: Begin moving files ** (desktop:14158): DEBUG: fileops_move: file 0: file:///home/ycl/dde/build/test_files/skype.desktop to dest: file:///home/ycl ** (desktop:14158): DEBUG: begin _move_files_async ** (desktop:14158): WARNING **: _move_files_async: 目标文件已存在 ** (desktop:14158): DEBUG: show_conflict_dialog ** (desktop:14158): DEBUG: __setup_dialog_labels ** (desktop:14158): DEBUG: src: 1373600136 ** (desktop:14158): DEBUG: src: 1373599855 (desktop:14158): fcitx-connection-DEBUG: _fcitx_connection_create_ic (desktop:14158): fcitx-connection-DEBUG: _fcitx_connection_connection_finished ** (desktop:14158): DEBUG: bus_method_call ** (desktop:14158): DEBUG: response : Cancel ** (desktop:14158): DEBUG: move_async: error handling end ** (desktop:14158): DEBUG: fileops_move: End moving files ** Message: move end
二、dentry_copy
extern void dentry_copy (ArrayContainer fs, GFile* dest);
而copy的调试信息:(copy有文件的文件夹)
------------先mkdir 然后chdir进入文件夹,然后开始依次copy
注:copy完后会come out dest文件夹
** Message: 0copy start ** (desktop:20038): DEBUG: fileops_copy: Begin copying files ** (desktop:20038): DEBUG: fileops_copy: file 0: file:///home/ycl/test_files to dest_dir: file:///home/ycl/dde/build ** (desktop:20038): DEBUG: _copy_files_async: mkdir : file:///home/ycl/dde/build/test_files ** (desktop:20038): DEBUG: _copy_files_async: copy file:///home/ycl/test_files to file:///home/ycl/dde/build/test_files ** (desktop:20038): DEBUG: traverse_directory: chdir to : file:///home/ycl/test_files ** (desktop:20038): DEBUG: traverse_directory: default_background.jpg ** (desktop:20038): DEBUG: dest_child_file_uri: file:///home/ycl/dde/build/test_files/default_background.jpg ** (desktop:20038): DEBUG: _copy_files_async: copy file:///home/ycl/test_files/default_background.jpg to file:///home/ycl/dde/build/test_files/default_background.jpg ** (desktop:20038): DEBUG: traverse_directory: test.desktop 。。。。。。。。。。。 (后面同理) ** (desktop:20788): DEBUG: _copy_files_async: copy file:///home/ycl/dde/build/test_files/brasero.desktop to file:///home/ycl/test_files/brasero.desktop ** (desktop:20788): DEBUG: traverse_directory: come out: file:///home/ycl/dde/build/test_files ** (desktop:20788): DEBUG: fileops_copy: End copying files ** Message: 2copy end
extern void dentry_copy (ArrayContainer fs, GFile* dest);
#Bug 当dest中存在要copy的src文件时,打印信息如下:
没有提示是否覆盖,也没有进行copy(无g_debug ("fileops_copy: file %d: %s to dest_dir: %s", i, src_uri, dest_dir_uri);打印信息)。
** Message: 0copy start ** (desktop:14712): DEBUG: fileops_copy: Begin copying files ** (desktop:14712): DEBUG: fileops_copy: End copying files ** Message: 0copy end
三、dentry_trash
extern void dentry_trash(ArrayContainer fs);
trash调试信息:(trash的是文件夹)
---------------——直接trash整个文件夹
** Message: 1trash start ** (desktop:20038): DEBUG: fileops_trash: Begin trashing files ** (desktop:20038): DEBUG: fileops_trash: file 0: file:///home/ycl/test_files ** (desktop:20038): DEBUG: _trash_files_async: trash : file:///home/ycl/test_files ** (desktop:20038): DEBUG: fileops_trash: End trashing files ** Message: 1trash end
注:在被trash的文件夹中直接cd ../ 是进入了trash目录,这说明了,trash相当于改变inode位置
ycl@ycl:~/test_files$ cd ../ ycl@ycl:~/.local/share/Trash/files$ l skype.2.desktop skype.4.desktop skype.6.desktop skype.8.desktop test_files/ skype.3.desktop skype.5.desktop skype.7.desktop skype.desktop
同时也说明,trash后,没有回到src的上一层目录。而是进入了trash文件夹。
#改进
此处是否有隐患??例如上面的 cd ../ ,当然如果桌面有app需要trash后用当前目录,但是却是~/.local/share/Trash/files 目录了。
四、dentry_delete
extern void dentry_delete_files(ArrayContainer fs, gboolean show_dialog);
delete的调试信息(delete带有文件的文件夹):
-----------------如下:先chdir 遍历进入文件夹,然后依次delete每个文件
最后come out,delete文件夹
** Message: 3delete start ** (desktop:20788): DEBUG: fileops_delete: Begin deleting files ** (desktop:20788): DEBUG: fileops_delete: file 0: file:///home/ycl/test_files ** (desktop:20788): DEBUG: traverse_directory: chdir to : file:///home/ycl/test_files ** (desktop:20788): DEBUG: traverse_directory: default_background.jpg ** (desktop:20788): DEBUG: _delete_files_async: delete : file:///home/ycl/test_files/default_background.jpg ** (desktop:20788): DEBUG: traverse_directory: test.desktop ** (desktop:20788): DEBUG: _delete_files_async: delete : file:///home/ycl/test_files/test.desktop ** (desktop:20788): DEBUG: traverse_directory: test ** (desktop:20788): DEBUG: _delete_files_async: delete : file:///home/ycl/test_files/test ** (desktop:20788): DEBUG: traverse_directory: test.coffee ** (desktop:20788): DEBUG: _delete_files_async: delete : file:///home/ycl/test_files/test.coffee 。。。。。。。。。。。。。。。。 iles/brasero.desktop ** (desktop:20788): DEBUG: traverse_directory: come out: file:///home/ycl/test_files ** (desktop:20788): DEBUG: _delete_files_async: delete : file:///home/ycl/test_files ** (desktop:20788): DEBUG: fileops_delete: End deleting files ** Message: 3delete end
对于单个文件的操作:
核心代码:
gpointer* _gp = g_object_ref(g_ptr_array_index(gappinfo,0)); ArrayContainer fs = {&_gp,1}; GFile* dest = g_file_new_for_uri("file:///home/ycl"); Test({ // g_message("move start"); dentry_move(fs,dest,FALSE); // g_message("move end"); // g_message("0copy start"); GFile* _dest0 = g_file_new_for_uri("file:///home/ycl/dde/build/test_files/"); GFile* _src0 = g_file_new_for_uri("file:///home/ycl/skype.desktop"); ArrayContainer _fs0; _fs0.data=&_src0; _fs0.num = 1; dentry_copy(_fs0,_dest0); g_object_unref(_dest0); ArrayContainer_free0(_fs0); // g_message("0copy end"); // g_message("1trash start"); GFile* _src1 = g_file_new_for_uri("file:///home/ycl/skype.desktop"); ArrayContainer _fs1; _fs1.data=&_src1; _fs1.num = 1; dentry_trash(_fs1); ArrayContainer_free0(_fs1); // g_message("1trash end");
打印信息:
[ 26%] Testing dentry_move...** (desktop:6902): DEBUG: fileops_move: Begin moving files ** (desktop:6902): DEBUG: fileops_move: file 0: file:///home/ycl/dde/build/test_files/skype.desktop to dest: file:///home/ycl ** (desktop:6902): DEBUG: begin _move_files_async ** (desktop:6902): DEBUG: _move_files_async: move file:///home/ycl/dde/build/test_files/skype.desktop to file:///home/ycl/skype.desktop ** (desktop:6902): DEBUG: fileops_delete: Begin deleting files ** (desktop:6902): DEBUG: fileops_delete: file 0: file:///home/ycl/dde/build/test_files/skype.desktop ** (desktop:6902): WARNING **: traverse_directory 1: 没有那个文件或目录 ** (desktop:6902): DEBUG: fileops_delete: End deleting files ** (desktop:6902): DEBUG: fileops_move: End moving files ** (desktop:6902): DEBUG: fileops_copy: Begin copying files ** (desktop:6902): DEBUG: fileops_copy: file 0: file:///home/ycl/skype.desktop to dest_dir: file:///home/ycl/dde/build/test_files ** (desktop:6902): DEBUG: _copy_files_async: copy file:///home/ycl/skype.desktop to file:///home/ycl/dde/build/test_files/skype.desktop ** (desktop:6902): DEBUG: fileops_copy: End copying files ** (desktop:6902): DEBUG: fileops_trash: Begin trashing files ** (desktop:6902): DEBUG: fileops_trash: file 0: file:///home/ycl/skype.desktop ** (desktop:6902): DEBUG: _trash_files_async: trash : file:///home/ycl/skype.desktop ** (desktop:6902): DEBUG: fileops_trash: End trashing files