From cf0956cad642d1151a9bcb69c43126862e29eed6 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sun, 18 Dec 2016 17:12:21 +0000 Subject: [PATCH] changed qse_fs_cpfile() to copy a directory that has been copied already --- qse/include/qse/si/fs.h | 50 +++++++------ qse/lib/si/fs-copy.c | 156 +++++++++++++++++++++++++++++----------- qse/lib/si/fs-delete.c | 63 ++++++---------- qse/lib/si/fs-prv.h | 10 +++ qse/lib/si/fs.c | 32 +++++++++ qse/samples/si/fs02.c | 35 +++++++-- qse/samples/si/fs03.c | 32 ++++++++- 7 files changed, 265 insertions(+), 113 deletions(-) diff --git a/qse/include/qse/si/fs.h b/qse/include/qse/si/fs.h index 1e67ff63..839f7662 100644 --- a/qse/include/qse/si/fs.h +++ b/qse/include/qse/si/fs.h @@ -97,7 +97,7 @@ typedef enum qse_fs_ent_type_t qse_fs_ent_type_t; struct qse_fs_ent_t { - int flags; + int flags; struct { @@ -176,29 +176,33 @@ enum qse_fs_trait_t typedef enum qse_fs_trait_t qse_fs_trait_t; -/** - * \return -1 on failure, 0 to cancel, 1 to keep copying - */ -typedef int (*qse_fs_cbs_cp_t) ( - qse_fs_t* fs, - const qse_char_t* srcpath, - const qse_char_t* dstpath, - qse_uintmax_t bytes_totoal, - qse_uintmax_t bytes_copied -); +enum qse_fs_action_t +{ + QSE_FS_CPFILE, + QSE_FS_RMFILE, + QSE_FS_MKDIR, + QSE_FS_RMDIR, + QSE_FS_RENFILE, + QSE_FS_SYMLINK +}; +typedef enum qse_fs_action_t qse_fs_action_t; /** - * \return -1 on failure, 0 to skip, 1 to delete + * \return -1 on failure, 0 on success */ -typedef int (*qse_fs_cbs_rm_t) ( - qse_fs_t* fs, - const qse_char_t* path +typedef int (*qse_fs_actcb_t) ( + qse_fs_t* fs, + qse_fs_action_t action, + const qse_char_t* srcpath, + const qse_char_t* dstpath, + qse_uintmax_t bytes_total, + qse_uintmax_t bytes_copied ); struct qse_fs_cbs_t { - qse_fs_cbs_rm_t rm; - qse_fs_cbs_cp_t cp; + qse_fs_actcb_t actcb; + /*qse_fs_querycb_t querycb;*/ }; typedef struct qse_fs_cbs_t qse_fs_cbs_t; @@ -217,6 +221,12 @@ struct qse_fs_t qse_uint8_t cpbuf[4096]; void* cfs; /* stack for recursive file copying */ + struct + { + void* ptr; + qse_size_t len; + qse_size_t capa; + } ddr; /* destination directores remembers while copying */ }; enum qse_fs_opt_t @@ -343,12 +353,6 @@ QSE_EXPORT int qse_fs_pop ( ); - - - - - - QSE_EXPORT int qse_fs_getattronfd ( qse_fs_t* fs, qse_fs_handle_t fd, diff --git a/qse/lib/si/fs-copy.c b/qse/lib/si/fs-copy.c index 845ae33e..02c53b93 100644 --- a/qse/lib/si/fs-copy.c +++ b/qse/lib/si/fs-copy.c @@ -35,6 +35,13 @@ #define CPFILE_DST_ATTR (1 << 29) #define CPFILE_DST_FSPATH_MERGED (1 << 30) +struct devino_t +{ + qse_uintmax_t dev; + qse_uintmax_t ino; +}; +typedef struct devino_t devino_t; + struct cpfile_t { int flags; @@ -42,9 +49,63 @@ struct cpfile_t qse_fs_char_t* dst_fspath; qse_fs_attr_t src_attr; qse_fs_attr_t dst_attr; + }; typedef struct cpfile_t cpfile_t; +static int is_dir_remembered (qse_fs_t* fs, qse_fs_attr_t* attr) +{ + qse_size_t i; + devino_t* di; + + di = (devino_t*)fs->ddr.ptr; + for (i = 0; i < fs->ddr.len; i++) + { + if (attr->dev == di->dev && attr->ino == di->ino) return 1; + } + + return 0; +} + +static int remember_dir_to_history (qse_fs_t* fs, qse_fs_attr_t* attr) +{ + qse_size_t i; + devino_t* di; + + di = (devino_t*)fs->ddr.ptr; + for (i = 0; i < fs->ddr.len; i++) + { + if (attr->dev == di->dev && attr->ino == di->ino) + { + fs->errnum = QSE_FS_EEXIST; + return -1; + } + } + +/* TODO: table baded lookup instead of sequential search? */ + if (fs->ddr.len >= fs->ddr.capa) + { + qse_size_t newcapa; + + newcapa = QSE_ALIGNTO(fs->ddr.capa + 1, 256); + di = (devino_t*)QSE_MMGR_REALLOC (fs->mmgr, di, newcapa * QSE_SIZEOF(*di)); + + if (!di) + { + fs->errnum = QSE_FS_ENOMEM; + return -1; + } + + fs->ddr.ptr = di; + fs->ddr.capa = newcapa; + } + + di[fs->ddr.len].dev = attr->dev; + di[fs->ddr.len].ino = attr->ino; + fs->ddr.len++; + + return 0; +} static int merge_dstdir_and_srcbase (qse_fs_t* fs, cpfile_t* cpfile) { @@ -168,7 +229,6 @@ static int copy_file_in_fs (qse_fs_t* fs, cpfile_t* cpfile) /* ------------------------------------------------------ */ #else - if ((cpfile->flags & QSE_FS_CPFILE_SYMLINK) && cpfile->src_attr.islnk) { @@ -196,8 +256,9 @@ static int copy_file_in_fs (qse_fs_t* fs, cpfile_t* cpfile) { if (cpfile->flags & QSE_FS_CPFILE_FORCE) { -/* TODO: call cbs.rm callback??? */ QSE_UNLINK (cpfile->dst_fspath); + if (fs->cbs.actcb && qse_fs_invokecb (fs, QSE_FS_RMFILE, cpfile->dst_fspath, QSE_NULL, 0, 0) <= -1) goto oops_1; + if (QSE_SYMLINK (tmpbuf, cpfile->dst_fspath) <= -1) { fs->errnum = qse_fs_syserrtoerrnum (fs, errno); @@ -205,25 +266,7 @@ static int copy_file_in_fs (qse_fs_t* fs, cpfile_t* cpfile) } } } - - if (fs->cbs.cp) - { - qse_char_t* srcpath = QSE_NULL, * dstpath = QSE_NULL; - int x = 1; - - srcpath = (qse_char_t*)make_str_with_fspath (fs, cpfile->src_fspath); - dstpath = (qse_char_t*)make_str_with_fspath (fs, cpfile->dst_fspath); - - if (srcpath && dstpath) - { - x = fs->cbs.cp (fs, srcpath, dstpath, cpfile->src_attr.size, cpfile->src_attr.size); - } - - if (srcpath) free_str_with_fspath (fs, cpfile->src_fspath, srcpath); - if (dstpath) free_str_with_fspath (fs, cpfile->dst_fspath, dstpath); - - if (x <= -1) goto oops_1; - } + if (fs->cbs.actcb && qse_fs_invokecb (fs, QSE_FS_SYMLINK, tmpbuf, cpfile->dst_fspath, 0, 0) <= -1) goto oops_1; QSE_MMGR_FREE (fs->mmgr, tmpbuf); return 0; @@ -262,7 +305,7 @@ static int copy_file_in_fs (qse_fs_t* fs, cpfile_t* cpfile) goto oops_2; } - if (fs->cbs.cp) + if (fs->cbs.actcb) { srcpath = (qse_char_t*)make_str_with_fspath (fs, cpfile->src_fspath); dstpath = (qse_char_t*)make_str_with_fspath (fs, cpfile->dst_fspath); @@ -276,7 +319,7 @@ static int copy_file_in_fs (qse_fs_t* fs, cpfile_t* cpfile) { if (bytes_copied == 0 && srcpath && dstpath) { - if (fs->cbs.cp (fs, srcpath, dstpath, cpfile->src_attr.size, bytes_copied) <= -1) goto oops_2; + if (fs->cbs.actcb (fs, QSE_FS_CPFILE, srcpath, dstpath, cpfile->src_attr.size, bytes_copied) <= -1) goto oops_2; } break; } @@ -293,7 +336,7 @@ static int copy_file_in_fs (qse_fs_t* fs, cpfile_t* cpfile) if (srcpath && dstpath) { - if (fs->cbs.cp (fs, srcpath, dstpath, cpfile->src_attr.size, bytes_copied) <= -1) goto oops_2; + if (fs->cbs.actcb (fs, QSE_FS_CPFILE, srcpath, dstpath, cpfile->src_attr.size, bytes_copied) <= -1) goto oops_2; /* TODO: skip, ignore, etc... */ } } @@ -396,12 +439,6 @@ static void pop_cfs (qse_fs_t* fs, cpfile_t* cpfile, qse_dir_t** dir) QSE_MMGR_FREE (fs->mmgr, cfs); } -static int can_copy_dir_into (qse_fs_t* fs, cpfile_t* cpfile) -{ -/* TODO: */ - return 1; -} - static int copy_file (qse_fs_t* fs, cpfile_t* cpfile) { #if defined(NO_RECURSION) @@ -454,6 +491,16 @@ start_over: goto oops; } + + if (is_dir_remembered (fs, &cpfile->src_attr)) + { + /* skip this source directory as it's one of the destination + * directores earlier. see the call to remember_dir_to_history() + * below. */ + goto skip_dir; + } + + /* both the source and the destion is a directory */ dir = qse_dir_open ( fs->mmgr, 0, (const qse_char_t*)cpfile->src_fspath, #if defined(QSE_FS_CHAR_IS_MCHAR) @@ -469,17 +516,20 @@ start_over: goto oops; } -/* TODO: check if the directory is beging copied into itself in advance...XXXXXXXXXXXXXXXXXXXXXX */ - if (qse_fs_mkdirsys (fs, cpfile->dst_fspath) <= -1) { /* it's ok if the destination directory already exists */ if (fs->errnum != QSE_FS_EEXIST) goto oops; } - if (!can_copy_dir_into (fs, cpfile)) + /* (re)load the attribute. */ + if (qse_fs_getattrsys (fs, cpfile->dst_fspath, &cpfile->dst_attr, QSE_FS_GETATTR_SYMLINK) <= -1) goto oops; + cpfile->flags |= CPFILE_DST_ATTR; + + if (remember_dir_to_history (fs, &cpfile->dst_attr) <= -1) { - fs->errnum = QSE_FS_EPERM; + /* if the directory has been copied once, fs->errnum should be QSE_FS_EEXIST */ + if (fs->errnum == QSE_FS_EEXIST) goto close_dir; goto oops; } @@ -532,8 +582,12 @@ start_over: #endif } + close_dir: qse_dir_close (dir); dir = QSE_NULL; + + skip_dir: + /* do nothing more */ ; } else { @@ -570,6 +624,7 @@ start_over: if (copy_file_in_fs (fs, cpfile) <= -1) goto oops; } +skip: #if defined(NO_RECURSION) if (fs->cfs) { @@ -636,6 +691,7 @@ oops: int qse_fs_cpfilembs (qse_fs_t* fs, const qse_mchar_t* srcpath, const qse_mchar_t* dstpath, int flags) { glob_ctx_t ctx; + int ret = 0; ctx.fs = fs; ctx.flags = flags; @@ -648,10 +704,8 @@ int qse_fs_cpfilembs (qse_fs_t* fs, const qse_mchar_t* srcpath, const qse_mchar_ if (qse_globmbs (srcpath, copy_file_for_glob, &ctx, DEFAULT_GLOB_FLAGS, fs->mmgr, fs->cmgr) <= -1) { if (fs->errnum == QSE_FS_ENOERR) fs->errnum = QSE_FS_EGLOB; - return -1; + ret = -1; } - - return 0; } else { @@ -659,13 +713,23 @@ int qse_fs_cpfilembs (qse_fs_t* fs, const qse_mchar_t* srcpath, const qse_mchar_ s.ptr = (qse_mchar_t*)srcpath; s.len = 0; /* not important */ /* let me use the glob callback function for simplicity */ - return copy_file_for_glob (&s, &ctx); + ret = copy_file_for_glob (&s, &ctx); } + + if (fs->ddr.ptr) + { + QSE_MMGR_FREE (fs->mmgr, fs->ddr.ptr); + fs->ddr.ptr = QSE_NULL; + fs->ddr.len = 0; + fs->ddr.capa = 0; + } + return ret; } int qse_fs_cpfilewcs (qse_fs_t* fs, const qse_wchar_t* srcpath, const qse_wchar_t* dstpath, int flags) { glob_ctx_t ctx; + int ret = 0; ctx.fs = fs; ctx.flags = flags; @@ -678,10 +742,8 @@ int qse_fs_cpfilewcs (qse_fs_t* fs, const qse_wchar_t* srcpath, const qse_wchar_ if (qse_globwcs (srcpath, copy_file_for_glob, &ctx, DEFAULT_GLOB_FLAGS, fs->mmgr, fs->cmgr) <= -1) { if (fs->errnum == QSE_FS_ENOERR) fs->errnum = QSE_FS_EGLOB; - return -1; + ret = -1; } - - return 0; } else { @@ -689,6 +751,16 @@ int qse_fs_cpfilewcs (qse_fs_t* fs, const qse_wchar_t* srcpath, const qse_wchar_ qse_wcstr_t s; s.ptr = (qse_wchar_t*)srcpath; s.len = 0; /* not important */ - return copy_file_for_glob (&s, &ctx); + ret = copy_file_for_glob (&s, &ctx); } + + if (fs->ddr.ptr) + { + QSE_MMGR_FREE (fs->mmgr, fs->ddr.ptr); + fs->ddr.ptr = QSE_NULL; + fs->ddr.len = 0; + fs->ddr.capa = 0; + } + + return ret; } diff --git a/qse/lib/si/fs-delete.c b/qse/lib/si/fs-delete.c index df879a0a..ccc1562f 100644 --- a/qse/lib/si/fs-delete.c +++ b/qse/lib/si/fs-delete.c @@ -127,10 +127,10 @@ static int delete_file (qse_fs_t* fs, const qse_char_t* path, int purge) qse_fs_char_t* fspath; int ret; - if (fs->cbs.rm) + if (fs->cbs.actcb) { int x; - x = fs->cbs.rm (fs, path); + x = fs->cbs.actcb (fs, QSE_FS_RMFILE, path, QSE_NULL, 0, 0); if (x <= -1) return -1; if (x == 0) return 0; /* skipped */ } @@ -184,10 +184,10 @@ static int delete_directory_nocbs (qse_fs_t* fs, const qse_char_t* path) static int delete_directory (qse_fs_t* fs, const qse_char_t* path) { - if (fs->cbs.rm) + if (fs->cbs.actcb) { int x; - x = fs->cbs.rm (fs, path); + x = fs->cbs.actcb (fs, QSE_FS_RMDIR, path, QSE_NULL, 0, 0); if (x <= -1) return -1; if (x == 0) return 0; /* skipped */ } @@ -276,70 +276,51 @@ static int purge_path (qse_fs_t* fs, const qse_char_t* path) static int delete_from_fs_with_mbs (qse_fs_t* fs, const qse_mchar_t* path, int dir) { qse_fs_char_t* fspath; - int ret; + int ret = 0; fspath = qse_fs_makefspathformbs (fs, path); if (!fspath) return -1; - if (fs->cbs.rm) + if (fs->cbs.actcb) { - qse_char_t* xpath; int x; - xpath = (qse_char_t*)make_str_with_mbs (fs, path); - if (!xpath) - { - fs->errnum = QSE_FS_ENOMEM; - return -1; - } + x = qse_fs_invokecb (fs, (dir? QSE_FS_RMDIR: QSE_FS_RMFILE), fspath, QSE_NULL, 0, 0); - x = fs->cbs.rm (fs, xpath); - - free_str_with_mbs (fs, path, xpath); - - if (x <= -1) return -1; - if (x == 0) return 0; /* skipped */ + if (x <= -1) { ret = -1; goto done; } + if (x == 0) goto done; /* skipped */ } ret = dir? qse_fs_rmdirsys (fs, fspath): qse_fs_rmfilesys (fs, fspath); +done: qse_fs_freefspathformbs (fs, path, fspath); - return ret; } static int delete_from_fs_with_wcs (qse_fs_t* fs, const qse_wchar_t* path, int dir) { qse_fs_char_t* fspath; - int ret; - - if (fs->cbs.rm) - { - qse_char_t* xpath; - int x; - - xpath = (qse_char_t*)make_str_with_wcs (fs, path); - if (!xpath) - { - fs->errnum = QSE_FS_ENOMEM; - return -1; - } - - x = fs->cbs.rm (fs, xpath); - - free_str_with_wcs (fs, path, xpath); - - if (x <= -1) return -1; - if (x == 0) return 0; /* skipped */ - } + int ret = 0; fspath = qse_fs_makefspathforwcs (fs, path); if (!fspath) return -1; + if (fs->cbs.actcb) + { + int x; + + x = qse_fs_invokecb (fs, (dir? QSE_FS_RMDIR: QSE_FS_RMFILE), fspath, QSE_NULL, 0, 0); + + if (x <= -1) { ret = -1; goto done; } + if (x == 0) goto done; /* skipped */ + } + ret = dir? qse_fs_rmdirsys (fs, fspath): qse_fs_rmfilesys (fs, fspath); +done: qse_fs_freefspathforwcs (fs, path, fspath); return ret; diff --git a/qse/lib/si/fs-prv.h b/qse/lib/si/fs-prv.h index e274baef..60803209 100644 --- a/qse/lib/si/fs-prv.h +++ b/qse/lib/si/fs-prv.h @@ -192,6 +192,16 @@ int qse_fs_rmdirsys ( const qse_fs_char_t* fspath ); + +int qse_fs_invokecb ( + qse_fs_t* fs, + qse_fs_action_t action, + qse_fs_char_t* src_fspath, + qse_fs_char_t* dst_fspath, + qse_uintmax_t bytes_total, + qse_uintmax_t bytes_done +); + #if defined(__cplusplus) } #endif diff --git a/qse/lib/si/fs.c b/qse/lib/si/fs.c index 2191d57f..8c2c9c73 100644 --- a/qse/lib/si/fs.c +++ b/qse/lib/si/fs.c @@ -823,3 +823,35 @@ void qse_fs_freefspathforwcs (qse_fs_t* fs, const qse_wchar_t* path, qse_fs_char } +int qse_fs_invokecb (qse_fs_t* fs, qse_fs_action_t action, qse_fs_char_t* src_fspath, qse_fs_char_t* dst_fspath, qse_uintmax_t bytes_total, qse_uintmax_t bytes_done) +{ + qse_char_t* srcpath = QSE_NULL, * dstpath = QSE_NULL; + int x = 1; + + if (src_fspath) + { + srcpath = (qse_char_t*)make_str_with_fspath (fs, src_fspath); + if (!srcpath) + { + x = -1; + goto done; + } + } + if (dst_fspath) + { + dstpath = (qse_char_t*)make_str_with_fspath (fs, dst_fspath); + if (!dstpath) + { + x = -1; + goto done; + } + } + + x = fs->cbs.actcb (fs, action, srcpath, dstpath, bytes_total, bytes_done); + +done: + if (srcpath) free_str_with_fspath (fs, cpfile->src_fspath, srcpath); + if (dstpath) free_str_with_fspath (fs, cpfile->dst_fspath, dstpath); + + return x; +} diff --git a/qse/samples/si/fs02.c b/qse/samples/si/fs02.c index 2a3f6118..bcc46f41 100644 --- a/qse/samples/si/fs02.c +++ b/qse/samples/si/fs02.c @@ -12,13 +12,40 @@ # include #endif -static int fs_rm (qse_fs_t* fs, const qse_char_t* path) +static int fs_actcb (qse_fs_t* fs, qse_fs_action_t act, const qse_char_t* srcpath, const qse_char_t* dstpath, qse_uintmax_t total, qse_uintmax_t done) { - qse_printf (QSE_T("Deleting [%s]\n"), path); + switch (act) + { + case QSE_FS_CPFILE: + if (total == done) qse_printf (QSE_T("Copied [%s] to [%s]\n"), srcpath, dstpath); + break; + + case QSE_FS_RMFILE: + qse_printf (QSE_T("Removed file [%s]\n"), srcpath); + break; + + case QSE_FS_SYMLINK: + qse_printf (QSE_T("Symlinked [%s] to [%s]\n"), srcpath, dstpath); + break; + + case QSE_FS_MKDIR: + qse_printf (QSE_T("Made directory [%s]\n"), srcpath); + break; + + case QSE_FS_RMDIR: + qse_printf (QSE_T("Removed directory [%s]\n"), srcpath); + break; + + case QSE_FS_RENFILE: + qse_printf (QSE_T("renamed [%s] to [%s]\n"), srcpath); + break; + } + /*if (qse_strcmp(path, QSE_T("b/c")) == 0) return 0;*/ - return 1; + return 1; } + static void print_usage (const qse_char_t* argv0) { qse_fprintf (QSE_STDERR, QSE_T("Usage: %s command filename\n"), qse_basename(argv0)); @@ -40,7 +67,7 @@ static int fs_main (int argc, qse_char_t* argv[]) fs = qse_fs_open (QSE_MMGR_GETDFL(), 0); qse_memset (&cbs, 0, QSE_SIZEOF(cbs)); - cbs.rm = fs_rm; + cbs.actcb = fs_actcb; qse_fs_setopt (fs, QSE_FS_CBS, &cbs); if (qse_strcmp(argv[1], QSE_T("rmfile")) == 0) diff --git a/qse/samples/si/fs03.c b/qse/samples/si/fs03.c index 51b3a5c0..3272278b 100644 --- a/qse/samples/si/fs03.c +++ b/qse/samples/si/fs03.c @@ -25,9 +25,35 @@ static void print_usage (const qse_char_t* argv0) qse_fprintf (QSE_STDERR, QSE_T(" -g glob\n")); } -static int fs_cp (qse_fs_t* fs, const qse_char_t* srcpath, const qse_char_t* dstpath, qse_uintmax_t total, qse_uintmax_t copied) +static int fs_actcb (qse_fs_t* fs, qse_fs_action_t act, const qse_char_t* srcpath, const qse_char_t* dstpath, qse_uintmax_t total, qse_uintmax_t done) { - if (total == copied) qse_printf (QSE_T("Copied [%s] to [%s]\n"), srcpath, dstpath); + switch (act) + { + case QSE_FS_CPFILE: + if (total == done) qse_printf (QSE_T("Copied [%s] to [%s]\n"), srcpath, dstpath); + break; + + case QSE_FS_RMFILE: + qse_printf (QSE_T("Removed file [%s]\n"), srcpath); + break; + + case QSE_FS_SYMLINK: + qse_printf (QSE_T("Symlinked [%s] to [%s]\n"), srcpath, dstpath); + break; + + case QSE_FS_MKDIR: + qse_printf (QSE_T("Made directory [%s]\n"), srcpath); + break; + + case QSE_FS_RMDIR: + qse_printf (QSE_T("Removed directory [%s]\n"), srcpath); + break; + + case QSE_FS_RENFILE: + qse_printf (QSE_T("renamed [%s] to [%s]\n"), srcpath); + break; + } + /*if (qse_strcmp(path, QSE_T("b/c")) == 0) return 0;*/ return 1; } @@ -93,7 +119,7 @@ static int fs_main (int argc, qse_char_t* argv[]) fs = qse_fs_open (QSE_MMGR_GETDFL(), 0); qse_memset (&cbs, 0, QSE_SIZEOF(cbs)); - cbs.cp = fs_cp; + cbs.actcb = fs_actcb; qse_fs_setopt (fs, QSE_FS_CBS, &cbs); if (qse_fs_cpfile (fs, argv[opt.ind], argv[opt.ind + 1], cpfile_flags) <= -1)