added fs-copy.c
This commit is contained in:
parent
1ef7fc2569
commit
11f364a6d0
543
qse/lib/cmn/fs-copy.c
Normal file
543
qse/lib/cmn/fs-copy.c
Normal file
@ -0,0 +1,543 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "fs.h"
|
||||
#include <qse/cmn/path.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include "mem.h"
|
||||
|
||||
/* internal flags. it must not overlap with qse_fs_cpfile_flag_t enumerators */
|
||||
#define CPFILE_DST_ATTR (1 << 27)
|
||||
#define CPFILE_DST_PATH_DUP (1 << 28)
|
||||
#define CPFILE_DST_FSPATH_DUP (1 << 29)
|
||||
#define CPFILE_DST_FSPATH_MERGED (1 << 30)
|
||||
|
||||
struct cpfile_t
|
||||
{
|
||||
int flags;
|
||||
|
||||
qse_fs_char_t* src_fspath;
|
||||
qse_fs_char_t* dst_fspath;
|
||||
|
||||
qse_char_t* src_path;
|
||||
qse_char_t* dst_path;
|
||||
|
||||
qse_fs_attr_t src_attr;
|
||||
qse_fs_attr_t dst_attr;
|
||||
};
|
||||
typedef struct cpfile_t cpfile_t;
|
||||
|
||||
static int merge_dstdir_and_file (qse_fs_t* fs, cpfile_t* cpfile)
|
||||
{
|
||||
qse_fs_char_t* fstmp;
|
||||
|
||||
/* if the destination is directory, copy the base name of the source
|
||||
* and append it to the end of the destination, targetting at an entry
|
||||
* in the directory */
|
||||
QSE_ASSERT (cpfile->dst_attr.isdir);
|
||||
|
||||
if (cpfile->dst_path)
|
||||
{
|
||||
qse_char_t* tmp;
|
||||
|
||||
tmp = qse_mergepathdup (cpfile->dst_path, qse_basename (cpfile->src_path), fs->mmgr);
|
||||
if (!tmp)
|
||||
{
|
||||
fs->errnum = QSE_FS_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cpfile->flags & CPFILE_DST_PATH_DUP)
|
||||
QSE_MMGR_FREE (fs->mmgr, cpfile->dst_path);
|
||||
|
||||
cpfile->dst_path = tmp;
|
||||
cpfile->flags |= CPFILE_DST_PATH_DUP;
|
||||
}
|
||||
|
||||
|
||||
fstmp = merge_fspath_dup (cpfile->dst_fspath, get_fspath_base (cpfile->src_fspath), fs->mmgr);
|
||||
if (!fstmp)
|
||||
{
|
||||
fs->errnum = QSE_FS_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cpfile->flags & CPFILE_DST_FSPATH_DUP)
|
||||
QSE_MMGR_FREE (fs->mmgr, cpfile->dst_fspath);
|
||||
cpfile->dst_fspath = fstmp;
|
||||
cpfile->flags |= CPFILE_DST_FSPATH_DUP;
|
||||
|
||||
if (qse_fs_getattr (fs, cpfile->dst_fspath, &cpfile->dst_attr) >= 0)
|
||||
{
|
||||
cpfile->flags |= CPFILE_DST_ATTR;
|
||||
}
|
||||
else
|
||||
{
|
||||
cpfile->flags &= ~CPFILE_DST_ATTR;
|
||||
}
|
||||
|
||||
cpfile->flags |= CPFILE_DST_FSPATH_MERGED;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
#if defined(_WIN32)
|
||||
DWORD copy_file_progress (
|
||||
LARGE_INTEGER TotalFileSize,
|
||||
LARGE_INTEGER TotalBytesTransferred,
|
||||
LARGE_INTEGER StreamSize,
|
||||
LARGE_INTEGER StreamBytesTransferred,
|
||||
DWORD dwStreamNumber,
|
||||
DWORD dwCallbackReason,
|
||||
HANDLE hSourceFile,
|
||||
HANDLE hDestinationFile,
|
||||
LPVOID lpData)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
/* copy
|
||||
* -> progress
|
||||
* -> abort/cancel
|
||||
* -> replace/overwrite
|
||||
* -> symbolic link
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && !defined(COPY_FILE_COPY_SYMLINK)
|
||||
/* winbase.h defines this only if _WIN32_WINNT >= 0x0600 */
|
||||
# define COPY_FILE_COPY_SYMLINK 0x00000800L
|
||||
#endif
|
||||
|
||||
static int copy_file_in_fs (qse_fs_t* fs, cpfile_t* cpfile)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
/* ------------------------------------------------------ */
|
||||
DWORD copy_flags = 0;
|
||||
|
||||
if (cpfile->flags & QSE_FS_CPFILE_SYMLINK)
|
||||
copy_flags |= COPY_FILE_COPY_SYMLINK;
|
||||
if (!(cpfile->flags & QSE_FS_CPFILE_REPLACE))
|
||||
copy_flags |= COPY_FILE_FAIL_IF_EXISTS;
|
||||
|
||||
/*
|
||||
if (fs->cbs.cp)
|
||||
{
|
||||
Specify callback???
|
||||
}
|
||||
*/
|
||||
|
||||
if (CopyFileEx (cpfile->src_fspath, cpfile->dst_fspath, QSE_NULL, QSE_NULL, QSE_NULL, copy_flags) == FALSE)
|
||||
{
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* ------------------------------------------------------ */
|
||||
|
||||
#elif defined(__OS2__)
|
||||
/* ------------------------------------------------------ */
|
||||
|
||||
APIRET rc;
|
||||
ULONG opmode = 0;
|
||||
|
||||
if (cpfile->flags & QSE_FS_CPFILE_REPLACE) opmode |= 1; /* set bit 0 */
|
||||
|
||||
rc = DosCopy (cpfile->src_fspath, cpfile->dst_fspath, opmode);
|
||||
if (rc != NO_ERROR)
|
||||
{
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/* ------------------------------------------------------ */
|
||||
|
||||
#elif defined(__DOS__)
|
||||
|
||||
/* ------------------------------------------------------ */
|
||||
|
||||
/* TOOD: IMPLEMENT THIS */
|
||||
fs->errnum = QSE_FS_ENOIMPL;
|
||||
return -1;
|
||||
|
||||
/* ------------------------------------------------------ */
|
||||
|
||||
#else
|
||||
if ((cpfile->flags & QSE_FS_CPFILE_SYMLINK) && cpfile->src_attr.islnk)
|
||||
{
|
||||
qse_fs_char_t* tmpbuf;
|
||||
|
||||
/* TODO: use a static buffer is size is small enough */
|
||||
tmpbuf = QSE_MMGR_ALLOC (fs->mmgr, QSE_SIZEOF(*tmpbuf) * (cpfile->src_attr.size + 1));
|
||||
if (tmpbuf == QSE_NULL)
|
||||
{
|
||||
fs->errnum = QSE_FS_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (QSE_READLINK (cpfile->src_fspath, tmpbuf, cpfile->src_attr.size) <= -1 ||
|
||||
QSE_SYMLINK (tmpbuf, cpfile->dst_fspath) <= -1)
|
||||
{
|
||||
QSE_MMGR_FREE (fs->mmgr, tmpbuf);
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
QSE_MMGR_FREE (fs->mmgr, tmpbuf);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int in = -1, out = -1;
|
||||
qse_ssize_t in_len, out_len;
|
||||
qse_uint8_t* bp;
|
||||
|
||||
in = QSE_OPEN (cpfile->src_fspath, O_RDONLY, 0);
|
||||
if (in <= -1)
|
||||
{
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, errno);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
out = QSE_OPEN (cpfile->dst_fspath, O_CREAT | O_WRONLY | O_TRUNC, 0777); /* TODO: proper mode */
|
||||
if (out <= -1 && (cpfile->flags & QSE_FS_CPFILE_FORCE))
|
||||
{
|
||||
/* if forced, delete it and try to open it again */
|
||||
QSE_UNLINK (cpfile->dst_fspath);
|
||||
out = QSE_OPEN (cpfile->dst_fspath, O_CREAT | O_WRONLY | O_TRUNC, 0777); /* TODO: proper mode */
|
||||
}
|
||||
if (out <= -1)
|
||||
{
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, errno);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
in_len = QSE_READ (in, fs->cpbuf, QSE_SIZEOF(fs->cpbuf));
|
||||
if (in_len <= 0) break;
|
||||
|
||||
/* TODO: call progress callback */
|
||||
|
||||
bp = fs->cpbuf;
|
||||
while (in_len > 0)
|
||||
{
|
||||
out_len = QSE_WRITE (out, bp, in_len);
|
||||
if (out_len <= -1) goto oops;
|
||||
bp += out_len;
|
||||
in_len -= out_len;
|
||||
}
|
||||
}
|
||||
|
||||
if (cpfile->flags & QSE_FS_CPFILE_PRESERVE)
|
||||
{
|
||||
#if defined(HAVE_FUTIMENS)
|
||||
struct timespec ts[2];
|
||||
#elif defined(HAVE_FUTIMES)
|
||||
struct timeval tv[2];
|
||||
#endif
|
||||
|
||||
if (QSE_FCHOWN (out, cpfile->src_attr.uid, cpfile->src_attr.gid) <= -1)
|
||||
{
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, errno);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
#if defined(HAVE_FUTIMENS)
|
||||
ts[0].tv_sec = cpfile->src_attr.atime.sec;
|
||||
ts[0].tv_nsec = cpfile->src_attr.atime.nsec;
|
||||
ts[1].tv_sec = cpfile->src_attr.mtime.sec;
|
||||
ts[1].tv_nsec = cpfile->src_attr.mtime.nsec;
|
||||
if (QSE_FUTIMENS (out, ts) <= -1)
|
||||
{
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, errno);
|
||||
goto oops;
|
||||
}
|
||||
#elif defined(HAVE_FUTIME)
|
||||
tv[0].tv_sec = cpfile->src_attr.atime.sec;
|
||||
tv[0].tv_usec = QSE_NSEC_TO_USEC(cpfile->src_attr.atime.nsec);
|
||||
tv[1].tv_sec = cpfile->src_attr.mtime.sec;
|
||||
tv[1].tv_usec = QSE_NSEC_TO_USEC(cpfile->src_attr.mtime.nsec);
|
||||
if (QSE_FUTIMES (out, tv) <= -1)
|
||||
{
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, errno);
|
||||
goto oops;
|
||||
}
|
||||
#else
|
||||
# error neither futimens nor futimes exist
|
||||
#endif
|
||||
}
|
||||
|
||||
QSE_CLOSE (out);
|
||||
QSE_CLOSE (in);
|
||||
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
if (out >= 0) QSE_CLOSE (out);
|
||||
if (in >= 0) QSE_CLOSE (in);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int copy_file (qse_fs_t* fs, cpfile_t* cpfile)
|
||||
{
|
||||
if (cpfile->src_attr.isdir)
|
||||
{
|
||||
/* source is a directory */
|
||||
|
||||
qse_dir_t* dir;
|
||||
qse_dir_errnum_t direrr;
|
||||
qse_dir_ent_t dirent;
|
||||
qse_char_t* src_path, * dst_path;
|
||||
int x;
|
||||
|
||||
copy_dir:
|
||||
if (cpfile->flags & CPFILE_DST_ATTR)
|
||||
{
|
||||
if (!cpfile->dst_attr.isdir)
|
||||
{
|
||||
/* cannot copy a directory to a file */
|
||||
fs->errnum = QSE_FS_ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(cpfile->flags & QSE_FS_CPFILE_NOTGTDIR) &&
|
||||
cpfile->dst_attr.isdir)
|
||||
{
|
||||
if (cpfile->flags & CPFILE_DST_FSPATH_MERGED)
|
||||
{
|
||||
/* merge_dstdir_and_file() has been called already.
|
||||
* no more getting into a subdirectory */
|
||||
fs->errnum = QSE_FS_EISDIR;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* arrange to copy a file into a directory */
|
||||
if (merge_dstdir_and_file (fs, cpfile) <= -1) return -1;
|
||||
goto copy_dir;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (!(cpfile->flags & QSE_FS_CPFILE_REPLACE))
|
||||
{
|
||||
fs->errnum = QSE_FS_EEXIST;
|
||||
return -1;
|
||||
}*/
|
||||
}
|
||||
|
||||
if (!(cpfile->flags & QSE_FS_CPFILE_RECURSIVE))
|
||||
{
|
||||
/* cann not copy a directory without recursion */
|
||||
fs->errnum = QSE_FS_EISDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = qse_dir_open (fs->mmgr, 0, cpfile->src_path, QSE_DIR_SKIPSPCDIR, &direrr);
|
||||
if (!dir)
|
||||
{
|
||||
fs->errnum = qse_fs_direrrtoerrnum (fs, direrr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qse_fs_sysmkdir (fs, cpfile->dst_fspath) <= -1)
|
||||
{
|
||||
qse_dir_close (dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
x = qse_dir_read (dir, &dirent);
|
||||
if (x <= -1)
|
||||
{
|
||||
fs->errnum = qse_fs_direrrtoerrnum (fs, qse_dir_geterrnum(dir));
|
||||
qse_dir_close (dir);
|
||||
return -1;
|
||||
}
|
||||
if (x == 0) break; /* no more entries */
|
||||
|
||||
|
||||
src_path = qse_mergepathdup (cpfile->src_path, dirent.name, fs->mmgr);
|
||||
dst_path = qse_mergepathdup (cpfile->dst_path, dirent.name, fs->mmgr);
|
||||
if (!src_path || !dst_path)
|
||||
{
|
||||
if (dst_path) QSE_MMGR_FREE (fs->mmgr, dst_path);
|
||||
if (src_path) QSE_MMGR_FREE (fs->mmgr, src_path);
|
||||
qse_dir_close (dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
x = qse_fs_cpfile (fs, src_path, dst_path, (cpfile->flags & QSE_FS_CPFILE_ALL));
|
||||
|
||||
QSE_MMGR_FREE (fs->mmgr, dst_path);
|
||||
QSE_MMGR_FREE (fs->mmgr, src_path);
|
||||
if (x <= -1)
|
||||
{
|
||||
qse_dir_close (dir);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
qse_dir_close (dir);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* source is a file */
|
||||
|
||||
copy_file:
|
||||
if (cpfile->flags & CPFILE_DST_ATTR)
|
||||
{
|
||||
if (cpfile->src_attr.ino == cpfile->dst_attr.ino &&
|
||||
cpfile->src_attr.dev == cpfile->dst_attr.dev)
|
||||
{
|
||||
/* cannot copy a file to itself */
|
||||
fs->errnum = QSE_FS_EINVAL; /* TODO: better error code */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(cpfile->flags & QSE_FS_CPFILE_NOTGTDIR) &&
|
||||
cpfile->dst_attr.isdir)
|
||||
{
|
||||
if (cpfile->flags & CPFILE_DST_FSPATH_MERGED)
|
||||
{
|
||||
/* merge_dstdir_and_file() has been called already.
|
||||
* no more getting into a subdirectory */
|
||||
fs->errnum = QSE_FS_EISDIR;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* arrange to copy a file into a directory */
|
||||
if (merge_dstdir_and_file (fs, cpfile) <= -1) return -1;
|
||||
goto copy_file;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cpfile->flags & QSE_FS_CPFILE_REPLACE))
|
||||
{
|
||||
fs->errnum = QSE_FS_EEXIST;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* both source and target are files */
|
||||
return copy_file_in_fs (fs, cpfile);
|
||||
}
|
||||
}
|
||||
|
||||
int qse_fs_cpfilembs (qse_fs_t* fs, const qse_mchar_t* srcpath, const qse_mchar_t* dstpath, int flags)
|
||||
{
|
||||
cpfile_t cpfile;
|
||||
int ret;
|
||||
|
||||
QSE_MEMSET (&cpfile, 0, QSE_SIZEOF(cpfile));
|
||||
|
||||
cpfile.flags = flags & QSE_FS_CPFILE_ALL; /* keep public flags only */
|
||||
|
||||
cpfile.src_fspath = (qse_fs_char_t*)qse_fs_makefspathformbs (fs, srcpath);
|
||||
cpfile.dst_fspath = (qse_fs_char_t*)qse_fs_makefspathformbs (fs, dstpath);
|
||||
cpfile.src_path = (qse_char_t*)make_str_with_mbs (fs, srcpath);
|
||||
cpfile.dst_path = (qse_char_t*)make_str_with_mbs (fs, dstpath);
|
||||
if (!cpfile.src_fspath || !cpfile.dst_fspath || !cpfile.src_path || !cpfile.dst_path) goto oops;
|
||||
|
||||
if (cpfile.dst_fspath != dstpath)
|
||||
{
|
||||
/* mark that it's been duplicated. */
|
||||
cpfile.flags |= CPFILE_DST_FSPATH_DUP;
|
||||
}
|
||||
|
||||
if (qse_fs_getattr (fs, cpfile.src_fspath, &cpfile.src_attr) <= -1) goto oops;
|
||||
if (qse_fs_getattr (fs, cpfile.dst_fspath, &cpfile.dst_attr) >= 0) cpfile.flags |= CPFILE_DST_ATTR;
|
||||
|
||||
ret = copy_file (fs, &cpfile);
|
||||
|
||||
free_str_with_mbs (fs, dstpath, cpfile.dst_path);
|
||||
free_str_with_mbs (fs, srcpath, cpfile.src_path);
|
||||
qse_fs_freefspathformbs (fs, dstpath, cpfile.dst_fspath);
|
||||
qse_fs_freefspathformbs (fs, srcpath, cpfile.src_fspath);
|
||||
return ret;
|
||||
|
||||
oops:
|
||||
if (cpfile.dst_path) free_str_with_mbs (fs, dstpath, cpfile.dst_path);
|
||||
if (cpfile.src_path) free_str_with_mbs (fs, srcpath, cpfile.src_path);
|
||||
if (cpfile.dst_fspath) qse_fs_freefspathformbs (fs, srcpath, cpfile.dst_fspath);
|
||||
if (cpfile.src_fspath) qse_fs_freefspathformbs (fs, dstpath, cpfile.src_fspath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int qse_fs_cpfilewcs (qse_fs_t* fs, const qse_wchar_t* srcpath, const qse_wchar_t* dstpath, int flags)
|
||||
{
|
||||
cpfile_t cpfile;
|
||||
int ret;
|
||||
|
||||
QSE_MEMSET (&cpfile, 0, QSE_SIZEOF(cpfile));
|
||||
|
||||
cpfile.flags = flags & QSE_FS_CPFILE_ALL; /* keep public flags only */
|
||||
|
||||
cpfile.src_fspath = (qse_fs_char_t*)qse_fs_makefspathforwcs (fs, srcpath);
|
||||
cpfile.dst_fspath = (qse_fs_char_t*)qse_fs_makefspathforwcs (fs, dstpath);
|
||||
cpfile.src_path = (qse_char_t*)make_str_with_wcs (fs, srcpath);
|
||||
cpfile.dst_path = (qse_char_t*)make_str_with_wcs (fs, dstpath);
|
||||
if (!cpfile.src_fspath || !cpfile.dst_fspath || !cpfile.src_path || !cpfile.dst_path) goto oops;
|
||||
|
||||
if (cpfile.dst_fspath != dstpath)
|
||||
{
|
||||
/* mark that it's been duplicated */
|
||||
cpfile.flags |= CPFILE_DST_FSPATH_DUP;
|
||||
}
|
||||
|
||||
if (qse_fs_getattr (fs, cpfile.src_fspath, &cpfile.src_attr) <= -1) goto oops;
|
||||
if (qse_fs_getattr (fs, cpfile.dst_fspath, &cpfile.dst_attr) >= 0) cpfile.flags |= CPFILE_DST_ATTR;
|
||||
|
||||
ret = copy_file (fs, &cpfile);
|
||||
|
||||
free_str_with_wcs (fs, dstpath, cpfile.dst_path);
|
||||
free_str_with_wcs (fs, srcpath, cpfile.src_path);
|
||||
qse_fs_freefspathforwcs (fs, dstpath, cpfile.dst_fspath);
|
||||
qse_fs_freefspathforwcs (fs, srcpath, cpfile.src_fspath);
|
||||
return ret;
|
||||
|
||||
oops:
|
||||
if (cpfile.dst_path) free_str_with_wcs (fs, dstpath, cpfile.dst_path);
|
||||
if (cpfile.src_path) free_str_with_wcs (fs, srcpath, cpfile.src_path);
|
||||
if (cpfile.dst_fspath) qse_fs_freefspathforwcs (fs, srcpath, cpfile.dst_fspath);
|
||||
if (cpfile.src_fspath) qse_fs_freefspathforwcs (fs, dstpath, cpfile.src_fspath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user