wrote a file copy function partially
This commit is contained in:
		| @ -117,6 +117,20 @@ struct qse_fs_ent_t | ||||
|  | ||||
| typedef struct qse_fs_ent_t qse_fs_ent_t; | ||||
|  | ||||
| struct qse_fs_attr_t | ||||
| { | ||||
| 	unsigned int isdir: 1; | ||||
| 	unsigned int islnk: 1; | ||||
| 	unsigned int isreg: 1; | ||||
| 	unsigned int isblk: 1; | ||||
| 	unsigned int ischr: 1; | ||||
| 	qse_uintmax_t size; | ||||
| 	qse_uintmax_t ino; | ||||
| 	qse_uintmax_t dev; | ||||
| }; | ||||
|  | ||||
| typedef struct qse_fs_attr_t qse_fs_attr_t; | ||||
|  | ||||
| typedef struct qse_fs_t qse_fs_t; | ||||
|  | ||||
| enum qse_fs_trait_t | ||||
| @ -129,6 +143,15 @@ 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, | ||||
| 	void*             ctx | ||||
| ); | ||||
|  | ||||
| /** | ||||
|  * \return -1 on failure, 0 to skip, 1 to delete | ||||
|  */ | ||||
| @ -155,6 +178,8 @@ struct qse_fs_t | ||||
| 	qse_fs_ent_t    ent; | ||||
| 	qse_char_t*     curdir; | ||||
| 	void*           info; | ||||
|  | ||||
| 	qse_uint8_t     cpbuf[4096]; | ||||
| }; | ||||
|  | ||||
|  | ||||
| @ -166,6 +191,16 @@ enum qse_fs_opt_t | ||||
| }; | ||||
| typedef enum qse_fs_opt_t qse_fs_opt_t; | ||||
|  | ||||
| enum qse_fs_cpfile_flag_t | ||||
| { | ||||
| 	QSE_FS_CPFILE_PRESERVE = (1 << 0), | ||||
| 	QSE_FS_CPFILE_REPLACE = (1 << 1), | ||||
| 	QSE_FS_CPFILE_SYMLINK = (1 << 2), | ||||
|  | ||||
| 	QSE_FS_CPFILE_ALL = (QSE_FS_CPFILE_PRESERVE | QSE_FS_CPFILE_REPLACE | QSE_FS_CPFILE_SYMLINK) | ||||
| }; | ||||
| typedef enum qse_fs_cpfile_flag_t qse_fs_cpfile_flag_t; | ||||
|  | ||||
|  | ||||
| enum qse_fs_mkdir_flag_t | ||||
| { | ||||
| @ -275,6 +310,26 @@ QSE_EXPORT int qse_fs_move ( | ||||
| ); | ||||
|  | ||||
|  | ||||
| QSE_EXPORT int qse_fs_cpfilembs ( | ||||
| 	qse_fs_t*          fs, | ||||
| 	const qse_mchar_t* srcpath, | ||||
| 	const qse_mchar_t* dstpath, | ||||
| 	int                flags | ||||
| ); | ||||
|  | ||||
| QSE_EXPORT int qse_fs_cpfilewcs ( | ||||
| 	qse_fs_t*          fs, | ||||
| 	const qse_wchar_t* srcpath, | ||||
| 	const qse_wchar_t* dstpath, | ||||
| 	int                flags | ||||
| ); | ||||
|  | ||||
| #if defined(QSE_CHAR_IS_MCHAR) | ||||
| #	define qse_fs_cpfile(fs,srcpath,dstpath,flags) qse_fs_cpfilembs(fs,srcpath,dstpath,flags) | ||||
| #else | ||||
| #	define qse_fs_cpfile(fs,srcpath,dstpath,flags) qse_fs_cpfilewcs(fs,srcpath,dstpath,flags) | ||||
| #endif | ||||
|  | ||||
| QSE_EXPORT int qse_fs_mkdirmbs ( | ||||
| 	qse_fs_t*          fs, | ||||
| 	const qse_mchar_t* path, | ||||
|  | ||||
| @ -123,6 +123,9 @@ qse_fs_errnum_t qse_fs_syserrtoerrnum (qse_fs_t* fs, qse_fs_syserr_t e) | ||||
| 		case ENOTDIR: | ||||
| 			return QSE_FS_ENOTDIR; | ||||
|  | ||||
| 		case EXDEV: | ||||
| 			return QSE_FS_EXDEV; | ||||
|  | ||||
| 		default: | ||||
| 			return QSE_FS_ESYSERR; | ||||
| 	} | ||||
|  | ||||
| @ -112,7 +112,7 @@ static int make_directory_chain (qse_fs_t* fs, qse_fs_char_t* fspath) | ||||
| 		if (IS_FSPATHSEP(*p)) | ||||
| 		{ | ||||
| 		#if defined(_WIN32) || defined(__DOS__) || defined(__OS2__) | ||||
| 			/* exclude the separtor from the path name */ | ||||
| 			/* exclude the separator from the path name */ | ||||
| 			c = *p; | ||||
| 			*p = QSE_FS_T('\0'); | ||||
| 		#else | ||||
| @ -153,6 +153,8 @@ int qse_fs_mkdirmbs (qse_fs_t* fs, const qse_mchar_t* path, int flags) | ||||
|  | ||||
| 	if (flags & QSE_FS_MKDIRMBS_PARENT) | ||||
| 	{ | ||||
| 		/* make_directory_chain changes the input path. | ||||
| 		 * ensure to create a modifiable string for it. */ | ||||
| 		fspath = qse_fs_dupfspathformbs (fs, path); | ||||
| 		if (!fspath) return -1; | ||||
|  | ||||
| @ -184,6 +186,8 @@ int qse_fs_mkdirwcs (qse_fs_t* fs, const qse_wchar_t* path, int flags) | ||||
|  | ||||
| 	if (flags & QSE_FS_MKDIRWCS_PARENT) | ||||
| 	{ | ||||
| 		/* make_directory_chain changes the input path. | ||||
| 		 * ensure to create a modifiable string for it. */ | ||||
| 		fspath = qse_fs_dupfspathforwcs (fs, path); | ||||
| 		if (!fspath) return -1; | ||||
|  | ||||
|  | ||||
| @ -51,25 +51,49 @@ struct fop_t | ||||
| #if defined(_WIN32) | ||||
| 	/* nothing yet */ | ||||
| #elif defined(__OS2__) | ||||
| 	qse_mchar_t* old_path; | ||||
| 	qse_mchar_t* new_path; | ||||
| 	qse_fs_char_t* old_path; | ||||
| 	qse_fs_char_t* new_path; | ||||
| #elif defined(__DOS__) | ||||
| 	qse_mchar_t* old_path; | ||||
| 	qse_mchar_t* new_path; | ||||
| 	qse_fs_char_t* old_path; | ||||
| 	qse_fs_char_t* new_path; | ||||
| #else | ||||
| 	qse_mchar_t* old_path; | ||||
| 	qse_mchar_t* new_path; | ||||
| 	qse_mchar_t* new_path2; | ||||
| 	qse_fs_char_t* old_path; | ||||
| 	qse_fs_char_t* new_path; | ||||
| 	qse_fs_char_t* new_path2; | ||||
|  | ||||
| 	#if defined(HAVE_LSTAT) | ||||
| 	qse_lstat_t old_stat; | ||||
| 	qse_lstat_t new_stat; | ||||
| 	#else | ||||
| 	qse_stat_t old_stat; | ||||
| 	qse_stat_t new_stat; | ||||
| 	#endif | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| typedef struct fop_t fop_t; | ||||
|  | ||||
| int qse_fs_move ( | ||||
| 	qse_fs_t* fs, const qse_char_t* oldpath, const qse_char_t* newpath) | ||||
|  | ||||
| /* internal flags. it must not overlap with qse_fs_cpfile_flag_t enumerators */ | ||||
| #define CPFILE_DST_ATTR (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; | ||||
|  | ||||
|  | ||||
| int qse_fs_move (qse_fs_t* fs, const qse_char_t* oldpath, const qse_char_t* newpath) | ||||
| { | ||||
|  | ||||
| #if defined(_WIN32) | ||||
| @ -208,7 +232,7 @@ int qse_fs_move ( | ||||
| 	fop.new_path = newpath; | ||||
| 	#else | ||||
| 	fop.old_path = qse_wcstombsdup (oldpath, QSE_NULL, fs->mmgr); | ||||
| 	fop.new_path = qse_wcstombsdup (newpath, QSE_NULL, fs->mmgr);	 | ||||
| 	fop.new_path = qse_wcstombsdup (newpath, QSE_NULL, fs->mmgr); | ||||
| 	if (fop.old_path == QSE_NULL || fop.old_path == QSE_NULL) | ||||
| 	{ | ||||
| 		fs->errnum = QSE_FS_ENOMEM; | ||||
| @ -363,3 +387,369 @@ oops: | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static int move_file_in_fs (qse_fs_t* fs, const qse_fs_char_t* oldpath, const qse_fs_char_t* newpath, int flags) | ||||
| { | ||||
| #if defined(_WIN32) | ||||
| 	/* ------------------------------------------------------ */ | ||||
|  | ||||
| 	if (MoveFile (oldpath, newpath) == FALSE) | ||||
| 	{ | ||||
| 		DWORD e = GetLastError(); | ||||
| 		if (e == ERROR_ALREADY_EXISTS) | ||||
| 		{ | ||||
| 			DeleteFile (newpath); | ||||
| 			if (MoveFile (oldpath, newpath) == FALSE) | ||||
| 			{ | ||||
| 				fs->errnum = qse_fs_syserrtoerrnum (fs, GetLastError()); | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			fs->errnum = qse_fs_syserrtoerrnum (fs, e); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| 	/* ------------------------------------------------------ */ | ||||
|  | ||||
| #elif defined(__OS2__) | ||||
| 	/* ------------------------------------------------------ */ | ||||
|  | ||||
| 	/* TODO: improve it */ | ||||
| 	APIRET rc; | ||||
|  | ||||
| 	rc = DosMove (oldpath, newpath); | ||||
| 	if (rc == ERROR_ALREADY_EXISTS || rc == ERROR_ACCESS_DENIED) | ||||
| 	{ | ||||
| 		DosDelete (fop.new_path); | ||||
| 		rc = DosMove (oldpath, newpath); | ||||
| 	} | ||||
| 	if (rc != NO_ERROR) | ||||
| 	{ | ||||
| 		fs->errnum = qse_fs_syserrtoerrnum (fs, rc); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| 	/* ------------------------------------------------------ */ | ||||
|  | ||||
| #elif defined(__DOS__) | ||||
|  | ||||
| 	/* ------------------------------------------------------ */ | ||||
| 	if (rename (oldpath, newpath) <= -1) | ||||
| 	{ | ||||
| 		/* FYI, rename() on watcom seems to set  | ||||
| 		 * errno to EACCES when the new path exists. */ | ||||
|  | ||||
| 		unlink (newpath); | ||||
| 		if (rename (oldpath, newpath) <= -1) | ||||
| 		{ | ||||
| 			fs->errnum = qse_fs_syserrtoerrnum (fs, errno); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| 	/* ------------------------------------------------------ */ | ||||
|  | ||||
| #else | ||||
|  | ||||
| 	if (!(flags & QSE_FS_CPFILE_REPLACE)) | ||||
| 	{ | ||||
| 		qse_lstat_t st; | ||||
| 		if (QSE_LSTAT (newpath, &st) >= 0) | ||||
| 		{ | ||||
| 			fs->errnum = QSE_FS_EEXIST; | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (QSE_RENAME (oldpath, newpath) == -1) | ||||
| 	{ | ||||
| 		fs->errnum = qse_fs_syserrtoerrnum (fs, errno); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
| #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 | ||||
|  */ | ||||
|  | ||||
| static int copy_file_in_fs (qse_fs_t* fs, const cpfile_t* cpfile) | ||||
| { | ||||
| #if defined(_WIN32) | ||||
| 	/* ------------------------------------------------------ */ | ||||
| 	DWORD copy_flags = 0; | ||||
|  | ||||
|  | ||||
| 	if (flags & QSE_FS_CPFILE_SYMLINK) | ||||
| 		copy_flags |= COPY_FILE_COPY_SYMLINK; | ||||
| 	if (!(flags & QSE_FS_CPFILE_REPLACE)) | ||||
| 		copy_flags |= COPY_FILE_FAIL_IF_EXISTS; | ||||
|  | ||||
| /* | ||||
| 	if (fs->cbs.cp) | ||||
| 	{ | ||||
| 		Specify callback??? | ||||
| 	} | ||||
| */ | ||||
|  | ||||
| 	if (CopyFileEx (oldpath, newpath,  QSE_NULL, QSE_NULL, QSE_NULL, copy_flags) == FALSE) | ||||
| 	{ | ||||
| 		fs->errnum = qse_fs_syserrtoerrnum (fs, e); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| 	/* ------------------------------------------------------ */ | ||||
|  | ||||
| #elif defined(__OS2__) | ||||
| 	/* ------------------------------------------------------ */ | ||||
|  | ||||
| 	APIRET rc; | ||||
| 	USHORT opmode = 0; | ||||
|  | ||||
| 	if (flags & QSE_FS_CPFILE_REPLACE) opmode |= 1; /* set bit 0 */ | ||||
|  | ||||
| 	rc = DosCopy (oldpath, newpath, opmode, 0); | ||||
| 	if (rc != NO_ERROR) | ||||
| 	{ | ||||
| 		fs->errnum = qse_fs_syserrtoerrnum (fs, rc); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| 	/* ------------------------------------------------------ */ | ||||
|  | ||||
| #elif defined(__DOS__) | ||||
|  | ||||
| 	/* ------------------------------------------------------ */ | ||||
| 	if (rename (oldpath, newpath) <= -1) | ||||
| 	{ | ||||
| 		/* FYI, rename() on watcom seems to set  | ||||
| 		 * errno to EACCES when the new path exists. */ | ||||
|  | ||||
| 		unlink (newpath); | ||||
| 		if (rename (oldpath, newpath) <= -1) | ||||
| 		{ | ||||
| 			fs->errnum = qse_fs_syserrtoerrnum (fs, errno); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| 	/* ------------------------------------------------------ */ | ||||
|  | ||||
| #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); | ||||
| 		out = QSE_OPEN (cpfile->dst_fspath, O_CREAT | O_WRONLY | O_TRUNC, 0777); /* TODO: proper mode */ | ||||
|  | ||||
| 		if (in <= -1 || 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; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		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) | ||||
| 	{ | ||||
| 		fs->errnum = QSE_FS_ENOIMPL; /* TODO: copy a directory into a  directory */ | ||||
| 		return -1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		/* TODO: check if it's itself */ | ||||
|  | ||||
| 		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->dst_attr.isdir) | ||||
| 			{ | ||||
| 				/* copy it to directory */ | ||||
| 				fs->errnum = QSE_FS_ENOIMPL; /* TODO: copy a file into a  directory */ | ||||
| 				return -1; | ||||
| 			} | ||||
|  | ||||
| 			if (!(cpfile->flags & QSE_FS_CPFILE_REPLACE)) | ||||
| 			{ | ||||
| 				fs->errnum = QSE_FS_EEXIST; | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (!cpfile->src_attr.isdir)  | ||||
| 		{ | ||||
| 			/* source is not a directory. */ | ||||
| 			return copy_file_in_fs (fs, cpfile); | ||||
| 		} | ||||
|  | ||||
| 		fs->errnum = QSE_FS_ENOIMPL; /* TODO: copy a file into a  directory */ | ||||
| 		return -1; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 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; /* 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); | ||||
| 	if (!cpfile.src_fspath || !cpfile.dst_fspath) goto oops; | ||||
|  | ||||
| 	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); | ||||
|  | ||||
| 	qse_fs_freefspathformbs (fs, dstpath, cpfile.dst_fspath); | ||||
| 	qse_fs_freefspathformbs (fs, srcpath, cpfile.src_fspath); | ||||
| 	return ret; | ||||
|  | ||||
| oops: | ||||
| 	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; /* 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); | ||||
| 	if (!cpfile.src_fspath || !cpfile.dst_fspath) goto oops; | ||||
|  | ||||
| 	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); | ||||
|  | ||||
| 	qse_fs_freefspathforwcs (fs, dstpath, cpfile.dst_fspath); | ||||
| 	qse_fs_freefspathforwcs (fs, srcpath, cpfile.src_fspath); | ||||
| 	return ret; | ||||
|  | ||||
| oops: | ||||
| 	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; | ||||
| } | ||||
|  | ||||
| @ -813,3 +813,49 @@ void qse_fs_freefspathforwcs (qse_fs_t* fs, const qse_wchar_t* path, qse_fs_char | ||||
| { | ||||
| 	if (path != (const qse_wchar_t*)fspath) QSE_MMGR_FREE (fs->mmgr, fspath); | ||||
| } | ||||
|  | ||||
|  | ||||
| int qse_fs_getattr (qse_fs_t* fs, const qse_fs_char_t* fspath, qse_fs_attr_t* attr) | ||||
| { | ||||
| #if defined(_WIN32) | ||||
| #error TODO | ||||
| #elif defined(__OS2__) | ||||
| #error TODO | ||||
| #elif defined(__DOS__) | ||||
| #error TODO | ||||
| #else | ||||
| 	#if defined(HAVE_LSTAT) | ||||
| 	qse_lstat_t st; | ||||
| 	#else | ||||
| 	qse_stat_t st; | ||||
| 	#endif | ||||
|  | ||||
| 	#if defined(HAVE_LSTAT) | ||||
| 	if (QSE_LSTAT (fspath, &st) == -1)  | ||||
| 	{ | ||||
| 		fs->errnum = qse_fs_syserrtoerrnum (fs, errno); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	#else | ||||
| 	/* is this ok to use stat? */ | ||||
| 	if (QSE_STAT (fspath, &st) == -1)  | ||||
| 	{ | ||||
| 		fs->errnum = qse_fs_syserrtoerrnum (fs, errno); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	#endif | ||||
|  | ||||
| 	QSE_MEMSET (attr, 0, QSE_SIZEOF(*attr)); | ||||
|  | ||||
| 	if (S_ISDIR(st.st_mode)) attr->isdir = 1; | ||||
| 	if (S_ISLNK(st.st_mode)) attr->islnk = 1; | ||||
| 	if (S_ISREG(st.st_mode)) attr->isreg = 1; | ||||
| 	if (S_ISBLK(st.st_mode)) attr->isblk = 1; | ||||
| 	if (S_ISCHR(st.st_mode)) attr->ischr = 1; | ||||
|  | ||||
| 	attr->size = st.st_size; | ||||
| 	attr->ino = st.st_ino; | ||||
| 	attr->dev = st.st_dev; | ||||
| 	return 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| @ -139,6 +139,13 @@ void qse_fs_freefspathforwcs ( | ||||
| #	define qse_fs_freefspath(fs,path,fspath) qse_fs_freefspathforwcs(fs,path,fspath); | ||||
| #endif | ||||
|  | ||||
|  | ||||
| int qse_fs_getattr ( | ||||
| 	qse_fs_t* fs, | ||||
| 	const qse_fs_char_t* fspath, | ||||
| 	qse_fs_attr_t* attr | ||||
| ); | ||||
|  | ||||
| #if defined(__cplusplus) | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -368,6 +368,12 @@ | ||||
| #	define QSE_SYMLINK(oldpath,newpath) symlink(oldpath,newpath) | ||||
| #endif | ||||
|  | ||||
| #if defined(SYS_readlink) && defined(QSE_USE_SYSCALL) | ||||
| #	define QSE_READLINK(path,buf,size) syscall(SYS_readlink,path,buf,size) | ||||
| #else | ||||
| #	define QSE_READLINK(path,buf,size) readlink(path,buf,size) | ||||
| #endif | ||||
|  | ||||
| #if defined(SYS_unlink) && defined(QSE_USE_SYSCALL) | ||||
| #	define QSE_UNLINK(path) syscall(SYS_unlink,path) | ||||
| #else | ||||
|  | ||||
| @ -18,6 +18,7 @@ bin_PROGRAMS = \ | ||||
| 	fmt02 \ | ||||
| 	fs01 \ | ||||
| 	fs02 \ | ||||
| 	fs03 \ | ||||
| 	htb \ | ||||
| 	glob01 \ | ||||
| 	ipad01 \ | ||||
|  | ||||
| @ -54,8 +54,8 @@ host_triplet = @host@ | ||||
| bin_PROGRAMS = chr01$(EXEEXT) dir01$(EXEEXT) dll$(EXEEXT) \ | ||||
| 	env01$(EXEEXT) fio01$(EXEEXT) fio02$(EXEEXT) fma$(EXEEXT) \ | ||||
| 	fmt01$(EXEEXT) fmt02$(EXEEXT) fs01$(EXEEXT) fs02$(EXEEXT) \ | ||||
| 	htb$(EXEEXT) glob01$(EXEEXT) ipad01$(EXEEXT) lda$(EXEEXT) \ | ||||
| 	main01$(EXEEXT) main02$(EXEEXT) mbwc01$(EXEEXT) \ | ||||
| 	fs03$(EXEEXT) htb$(EXEEXT) glob01$(EXEEXT) ipad01$(EXEEXT) \ | ||||
| 	lda$(EXEEXT) main01$(EXEEXT) main02$(EXEEXT) mbwc01$(EXEEXT) \ | ||||
| 	mbwc02$(EXEEXT) nwad01$(EXEEXT) nwif01$(EXEEXT) \ | ||||
| 	nwif02$(EXEEXT) oht$(EXEEXT) path01$(EXEEXT) pio$(EXEEXT) \ | ||||
| 	pma$(EXEEXT) rex01$(EXEEXT) rbt$(EXEEXT) sio01$(EXEEXT) \ | ||||
| @ -131,6 +131,10 @@ fs02_SOURCES = fs02.c | ||||
| fs02_OBJECTS = fs02.$(OBJEXT) | ||||
| fs02_LDADD = $(LDADD) | ||||
| fs02_DEPENDENCIES = $(am__DEPENDENCIES_2) | ||||
| fs03_SOURCES = fs03.c | ||||
| fs03_OBJECTS = fs03.$(OBJEXT) | ||||
| fs03_LDADD = $(LDADD) | ||||
| fs03_DEPENDENCIES = $(am__DEPENDENCIES_2) | ||||
| am_glob01_OBJECTS = glob01.$(OBJEXT) | ||||
| glob01_OBJECTS = $(am_glob01_OBJECTS) | ||||
| glob01_LDADD = $(LDADD) | ||||
| @ -272,7 +276,7 @@ am__v_GEN_0 = @echo "  GEN   " $@; | ||||
| SOURCES = $(chr01_SOURCES) dir01.c $(dll_SOURCES) $(env01_SOURCES) \ | ||||
| 	$(fio01_SOURCES) $(fio02_SOURCES) $(fma_SOURCES) \ | ||||
| 	$(fmt01_SOURCES) $(fmt02_SOURCES) $(fs01_SOURCES) fs02.c \ | ||||
| 	$(glob01_SOURCES) $(htb_SOURCES) $(ipad01_SOURCES) \ | ||||
| 	fs03.c $(glob01_SOURCES) $(htb_SOURCES) $(ipad01_SOURCES) \ | ||||
| 	$(lda_SOURCES) $(main01_SOURCES) $(main02_SOURCES) \ | ||||
| 	$(mbwc01_SOURCES) $(mbwc02_SOURCES) $(nwad01_SOURCES) nwif01.c \ | ||||
| 	nwif02.c $(oht_SOURCES) $(path01_SOURCES) $(pio_SOURCES) \ | ||||
| @ -283,7 +287,7 @@ SOURCES = $(chr01_SOURCES) dir01.c $(dll_SOURCES) $(env01_SOURCES) \ | ||||
| DIST_SOURCES = $(chr01_SOURCES) dir01.c $(dll_SOURCES) \ | ||||
| 	$(env01_SOURCES) $(fio01_SOURCES) $(fio02_SOURCES) \ | ||||
| 	$(fma_SOURCES) $(fmt01_SOURCES) $(fmt02_SOURCES) \ | ||||
| 	$(fs01_SOURCES) fs02.c $(glob01_SOURCES) $(htb_SOURCES) \ | ||||
| 	$(fs01_SOURCES) fs02.c fs03.c $(glob01_SOURCES) $(htb_SOURCES) \ | ||||
| 	$(ipad01_SOURCES) $(lda_SOURCES) $(main01_SOURCES) \ | ||||
| 	$(main02_SOURCES) $(mbwc01_SOURCES) $(mbwc02_SOURCES) \ | ||||
| 	$(nwad01_SOURCES) nwif01.c nwif02.c $(oht_SOURCES) \ | ||||
| @ -628,6 +632,9 @@ fs01$(EXEEXT): $(fs01_OBJECTS) $(fs01_DEPENDENCIES) $(EXTRA_fs01_DEPENDENCIES) | ||||
| fs02$(EXEEXT): $(fs02_OBJECTS) $(fs02_DEPENDENCIES) $(EXTRA_fs02_DEPENDENCIES)  | ||||
| 	@rm -f fs02$(EXEEXT) | ||||
| 	$(AM_V_CCLD)$(LINK) $(fs02_OBJECTS) $(fs02_LDADD) $(LIBS) | ||||
| fs03$(EXEEXT): $(fs03_OBJECTS) $(fs03_DEPENDENCIES) $(EXTRA_fs03_DEPENDENCIES)  | ||||
| 	@rm -f fs03$(EXEEXT) | ||||
| 	$(AM_V_CCLD)$(LINK) $(fs03_OBJECTS) $(fs03_LDADD) $(LIBS) | ||||
| glob01$(EXEEXT): $(glob01_OBJECTS) $(glob01_DEPENDENCIES) $(EXTRA_glob01_DEPENDENCIES)  | ||||
| 	@rm -f glob01$(EXEEXT) | ||||
| 	$(AM_V_CCLD)$(LINK) $(glob01_OBJECTS) $(glob01_LDADD) $(LIBS) | ||||
| @ -730,6 +737,7 @@ distclean-compile: | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmt02.Po@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs01.Po@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs02.Po@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs03.Po@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glob01.Po@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htb.Po@am__quote@ | ||||
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipad01.Po@am__quote@ | ||||
|  | ||||
							
								
								
									
										93
									
								
								qse/samples/cmn/fs03.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								qse/samples/cmn/fs03.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | ||||
| #include <qse/cmn/fs.h> | ||||
| #include <qse/cmn/mem.h> | ||||
| #include <qse/cmn/str.h> | ||||
| #include <qse/cmn/sio.h> | ||||
| #include <qse/cmn/path.h> | ||||
| #include <qse/cmn/main.h> | ||||
| #include <qse/cmn/mbwc.h> | ||||
| #include <locale.h> | ||||
|  | ||||
|  | ||||
| static void print_usage (const qse_char_t* argv0) | ||||
| { | ||||
| 	qse_fprintf (QSE_STDERR, QSE_T("Usage: %s command filename filename\n"), qse_basename(argv0)); | ||||
| 	qse_fprintf (QSE_STDERR, QSE_T("Command is one of cpfile | cpfile-s\n")); | ||||
| 	qse_fprintf (QSE_STDERR, QSE_T("Filename is a pattern for delXXX\n")); | ||||
| } | ||||
|  | ||||
| static int fs_main (int argc, qse_char_t* argv[]) | ||||
| { | ||||
| 	qse_fs_t* fs; | ||||
| 	qse_fs_cbs_t cbs; | ||||
| 	int ret = 0; | ||||
|  | ||||
| 	if (argc != 4) | ||||
| 	{ | ||||
| 		print_usage (argv[0]); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	fs = qse_fs_open (QSE_MMGR_GETDFL(), 0); | ||||
|  | ||||
| /* | ||||
| 	qse_memset (&cbs, 0, QSE_SIZEOF(cbs)); | ||||
| 	cbs.del = fs_del; | ||||
| 	qse_fs_setopt (fs, QSE_FS_CBS, &cbs); | ||||
| */ | ||||
|  | ||||
| 	if (qse_strcmp(argv[1], QSE_T("cpfile")) == 0) | ||||
| 	{ | ||||
| 		if (qse_fs_cpfile (fs, argv[2], argv[3], 0) <= -1) | ||||
| 		{ | ||||
| 			qse_fprintf (QSE_STDERR, QSE_T("cannot copy file - %d\n"), qse_fs_geterrnum(fs)); | ||||
| 			ret = -1; | ||||
| 		} | ||||
| 	} | ||||
| 	else if (qse_strcmp(argv[1], QSE_T("cpfile-s")) == 0) | ||||
| 	{ | ||||
| 		if (qse_fs_cpfile (fs, argv[2], argv[3], QSE_FS_CPFILE_SYMLINK) <= -1) | ||||
| 		{ | ||||
| 			qse_fprintf (QSE_STDERR, QSE_T("cannot copy file - %d\n"), qse_fs_geterrnum(fs)); | ||||
| 			ret = -1; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		print_usage (argv[0]); | ||||
| 		ret = -1; | ||||
| 	} | ||||
|  | ||||
| 	qse_fs_close (fs); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int main (int argc, qse_achar_t* argv[]) | ||||
| { | ||||
| 	int x; | ||||
| #if defined(_WIN32) | ||||
|  	char locale[100]; | ||||
| 	UINT codepage = GetConsoleOutputCP(); | ||||
| 	if (codepage == CP_UTF8) | ||||
| 	{ | ||||
| 		/*SetConsoleOUtputCP (CP_UTF8);*/ | ||||
| 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		sprintf (locale, ".%u", (unsigned int)codepage); | ||||
| 		setlocale (LC_ALL, locale); | ||||
| 		qse_setdflcmgrbyid (QSE_CMGR_SLMB); | ||||
| 	} | ||||
| #else | ||||
| 	setlocale (LC_ALL, ""); | ||||
| 	qse_setdflcmgrbyid (QSE_CMGR_SLMB); | ||||
| #endif | ||||
|  | ||||
| 	qse_openstdsios (); | ||||
|  | ||||
| 	x = qse_runmain (argc, argv, fs_main); | ||||
|  | ||||
| 	qse_closestdsios (); | ||||
|  | ||||
| 	return x; | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user