mirror of
https://github.com/troglobit/libite.git
synced 2026-11-09 16:21:18 +00:00
Refactor copyfile(), and copy_filep() --> fcopyfile() to use same backend.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
1 parent
1423edc044
commit
af39ae5fa9
2 files changed
+97
-116
No files matched your search
+92
-114
@@ -23,23 +23,71 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "lite.h"
|
#include "lite.h"
|
||||||
|
|
||||||
static int adjust_target(char *src, char **dst);
|
|
||||||
|
/* Tests if dst is a directory, if so, reallocates dst and appends src filename returning 1 */
|
||||||
|
static int adjust_target(char *src, char **dst)
|
||||||
|
{
|
||||||
|
int isdir = 0;
|
||||||
|
|
||||||
|
if (fisdir(*dst)) {
|
||||||
|
int slash = 0;
|
||||||
|
char *tmp, *ptr = strrchr(src, '/');
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
ptr = src;
|
||||||
|
else
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
tmp = malloc(strlen(*dst) + strlen(ptr) + 2);
|
||||||
|
if (!tmp) {
|
||||||
|
errno = EISDIR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
isdir = 1; /* Free dst before exit! */
|
||||||
|
slash = fisslashdir(*dst);
|
||||||
|
|
||||||
|
sprintf(tmp, "%s%s%s", *dst, slash ? "" : "/", ptr);
|
||||||
|
*dst = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Actual copy loop, used by both copyfile() and fcopyfile()
|
||||||
|
* breaks loop on error and EOF */
|
||||||
|
static ssize_t do_copy(int in, int out, size_t num, char *buffer, size_t len)
|
||||||
|
{
|
||||||
|
ssize_t ret = 0, size = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
size_t count = num > len ? len : num;
|
||||||
|
|
||||||
|
ret = read(in, buffer, count);
|
||||||
|
if (ret <= 0) {
|
||||||
|
if (ret == -1 && EINTR == errno)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret > 0)
|
||||||
|
size += write(out, buffer, ret);
|
||||||
|
num -= count;
|
||||||
|
} while (num > 0);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* copyfile - Copy a file to another.
|
* copyfile - Copy a file to another.
|
||||||
* @src: Source file.
|
* @src: Full path name to source file.
|
||||||
* @dst: Target file.
|
* @dst: Full path name to target file.
|
||||||
* @len: Number of bytes to copy, zero (0) for entire file.
|
* @len: Number of bytes to copy, zero (0) for entire file.
|
||||||
* @sym: Should symlinks be recreated (1) or followed (0)
|
* @sym: Should symlinks be recreated (1) or followed (0)
|
||||||
*
|
*
|
||||||
@@ -48,19 +96,18 @@ static int adjust_target(char *src, char **dst);
|
|||||||
* the finit project, http://helllabs.org/finit/, which is a reimplementation
|
* the finit project, http://helllabs.org/finit/, which is a reimplementation
|
||||||
* of fastinit for the Asus EeePC.
|
* of fastinit for the Asus EeePC.
|
||||||
*
|
*
|
||||||
* Only some small changes to save stack space have been introduced.
|
|
||||||
*
|
|
||||||
* Returns:
|
* Returns:
|
||||||
* The number of bytes copied, zero may be error (check errno!), but it
|
* The number of bytes copied, zero may be error (check errno!), but it
|
||||||
* may also indicate that @src was empty. If @src is a directory errno
|
* may also indicate that @src was empty. If @src is a directory @errno
|
||||||
* will be set to %EISDIR since copyfile() is not recursive. If @src
|
* will be set to %EISDIR since copyfile() is not recursive.
|
||||||
*/
|
*/
|
||||||
ssize_t copyfile(char *src, char *dst, int len, int sym)
|
ssize_t copyfile(char *src, char *dst, int len, int sym)
|
||||||
{
|
{
|
||||||
char *buffer;
|
char *buffer;
|
||||||
int in, out, isdir = 0, saved_errno = 0;
|
int in, out, isdir = 0, saved_errno = 0;
|
||||||
ssize_t num, size = 0;
|
size_t num;
|
||||||
struct stat sb;
|
ssize_t size = 0;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
@@ -77,13 +124,13 @@ ssize_t copyfile(char *src, char *dst, int len, int sym)
|
|||||||
isdir = adjust_target(src, &dst);
|
isdir = adjust_target(src, &dst);
|
||||||
|
|
||||||
/* Check if the source file is a symlink ... */
|
/* Check if the source file is a symlink ... */
|
||||||
if (stat(src, &sb)) {
|
if (stat(src, &st)) {
|
||||||
size = -1;
|
size = -1;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ... only try readlink() if symlink and @sym is set. */
|
/* ... only try readlink() if symlink and @sym is set. */
|
||||||
if (sym && (sb.st_mode & S_IFMT) == S_IFLNK) {
|
if (sym && (st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
size = readlink(src, buffer, BUFSIZ);
|
size = readlink(src, buffer, BUFSIZ);
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
if (size >= (ssize_t)BUFSIZ) {
|
if (size >= (ssize_t)BUFSIZ) {
|
||||||
@@ -102,7 +149,9 @@ ssize_t copyfile(char *src, char *dst, int len, int sym)
|
|||||||
|
|
||||||
/* 0: copy entire file */
|
/* 0: copy entire file */
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
len = INT_MAX; /* XXX: 2047 MiB should sufficient ... */
|
num = st.st_size;
|
||||||
|
else
|
||||||
|
num = (size_t)len;
|
||||||
|
|
||||||
in = open(src, O_RDONLY);
|
in = open(src, O_RDONLY);
|
||||||
if (in < 0) {
|
if (in < 0) {
|
||||||
@@ -117,14 +166,9 @@ ssize_t copyfile(char *src, char *dst, int len, int sym)
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
size = do_copy(in, out, num, buffer, BUFSIZ);
|
||||||
int clen = len > BUFSIZ ? BUFSIZ : len;
|
if (!size && errno)
|
||||||
|
saved_errno = errno;
|
||||||
num = read(in, buffer, clen);
|
|
||||||
if (num > 0)
|
|
||||||
size += write(out, buffer, num);
|
|
||||||
len -= clen;
|
|
||||||
} while (len > 0 && num == BUFSIZ);
|
|
||||||
|
|
||||||
close(out);
|
close(out);
|
||||||
close(in);
|
close(in);
|
||||||
@@ -164,7 +208,7 @@ int movefile(char *src, char *dst)
|
|||||||
if (rename(src, dst)) {
|
if (rename(src, dst)) {
|
||||||
if (errno == EXDEV) {
|
if (errno == EXDEV) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
copyfile(src, dst, 0, 0);
|
copyfile(src, dst, 0, 1);
|
||||||
if (errno)
|
if (errno)
|
||||||
result = 1;
|
result = 1;
|
||||||
else
|
else
|
||||||
@@ -181,107 +225,42 @@ int movefile(char *src, char *dst)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* copy_filep - Copy between FILE *fp.
|
* fcopyfile - Copy between FILE *fp.
|
||||||
* @src: Source FILE.
|
* @src: Source FILE.
|
||||||
* @dst: Destination FILE.
|
* @dst: Destination FILE.
|
||||||
*
|
*
|
||||||
* Function takes signals into account and will restart the syscalls as long
|
* Function takes signals into account and will restart the syscalls as
|
||||||
* as error is %EINTR.
|
* long as error is %EINTR.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* POSIX OK(0), or non-zero with errno set on error.
|
* POSIX OK(0), or non-zero with errno set on error.
|
||||||
*/
|
*/
|
||||||
int copy_filep(FILE *src, FILE *dst)
|
int fcopyfile(FILE *src, FILE *dst)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int ret;
|
||||||
char *buf;
|
char *buffer;
|
||||||
|
|
||||||
if (!src || !dst)
|
if (!src || !dst) {
|
||||||
return EINVAL;
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
buf = (char *)malloc(BUFSIZ);
|
|
||||||
if (!buf)
|
|
||||||
return errno;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
errno = 0;
|
|
||||||
if (!fgets(buf, BUFSIZ, src)) {
|
|
||||||
if (errno == EINTR) {
|
|
||||||
clearerr(src);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (feof(src))
|
|
||||||
break;
|
|
||||||
|
|
||||||
result = errno;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (EOF == fputs(buf, dst)) {
|
|
||||||
if (errno == EINTR) {
|
|
||||||
clearerr(dst);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = errno;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
buffer = malloc(BUFSIZ);
|
||||||
free(buf);
|
if (!buffer)
|
||||||
return errno = result;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
/* Tests if dst is a directory, if so, reallocates dst and appends src filename returning 1 */
|
ret = do_copy(fileno(src), fileno(dst), BUFSIZ, buffer, BUFSIZ);
|
||||||
static int adjust_target(char *src, char **dst)
|
if (ret > 0)
|
||||||
{
|
ret = 0;
|
||||||
int isdir = 0;
|
else if (errno)
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
if (fisdir(*dst)) {
|
free(buffer);
|
||||||
int slash = 0;
|
|
||||||
char *tmp, *ptr = strrchr(src, '/');
|
|
||||||
|
|
||||||
if (!ptr)
|
return ret;
|
||||||
ptr = src;
|
|
||||||
else
|
|
||||||
ptr++;
|
|
||||||
|
|
||||||
tmp = malloc(strlen(*dst) + strlen(ptr) + 2);
|
|
||||||
if (!tmp) {
|
|
||||||
errno = EISDIR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
isdir = 1; /* Free dst before exit! */
|
|
||||||
slash = fisslashdir(*dst);
|
|
||||||
|
|
||||||
sprintf(tmp, "%s%s%s", *dst, slash ? "" : "/", ptr);
|
|
||||||
*dst = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isdir;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UNITTEST
|
#ifdef UNITTEST
|
||||||
#include <stdio.h>
|
|
||||||
/* XXX: Make a real set of unit tests ... */
|
|
||||||
#if 0
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
if (argc < 3) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Usage: %s <src> <dst>\nCopies the <src> file to the <dst> file.\n",
|
|
||||||
argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Copying file %s to %s\n", argv[1], argv[2]);
|
|
||||||
|
|
||||||
return copyfile(argv[1], argv[2], 0, 0);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -295,11 +274,11 @@ int main(void)
|
|||||||
|
|
||||||
fprintf(stderr, "\n=>Start testing copy_filep()\n");
|
fprintf(stderr, "\n=>Start testing copy_filep()\n");
|
||||||
while (files[i]) {
|
while (files[i]) {
|
||||||
fprintf(stderr, "copy_filep(%s, %s)\t", files[i],
|
fprintf(stderr, "fcopyfile(%s, %s)\t", files[i],
|
||||||
files[i + 1]);
|
files[i + 1]);
|
||||||
src = fopen(files[i], "r");
|
src = fopen(files[i], "r");
|
||||||
dst = fopen(files[i + 1], "w");
|
dst = fopen(files[i + 1], "w");
|
||||||
if (copy_filep(src, dst))
|
if (fcopyfile(src, dst))
|
||||||
perror("Failed");
|
perror("Failed");
|
||||||
|
|
||||||
if (src)
|
if (src)
|
||||||
@@ -330,12 +309,11 @@ int main(void)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#endif /* UNITTEST */
|
#endif /* UNITTEST */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* compile-command: "gcc -g -I../include -o copy -DUNITTEST copyfile.c fisdir.c fexist.c fmode.c && ./copy"
|
* compile-command: "gcc -g -o coppa -DUNITTEST copyfile.c fisdir.c fexist.c fmode.c && ./coppa"
|
||||||
* version-control: t
|
* version-control: t
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Collection of utility funcs and C library extensions for finit & its plugins
|
/* Collection of utility funcs and C library extensions for finit & its plugins
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -42,7 +42,7 @@ mode_t fmode (char *file);
|
|||||||
FILE *tempfile (void);
|
FILE *tempfile (void);
|
||||||
ssize_t copyfile (char *src, char *dst, int len, int sym);
|
ssize_t copyfile (char *src, char *dst, int len, int sym);
|
||||||
int movefile (char *src, char *dst);
|
int movefile (char *src, char *dst);
|
||||||
int copy_filep (FILE *src, FILE *dst);
|
int fcopyfile (FILE *src, FILE *dst);
|
||||||
size_t fsendfile (FILE *out, FILE *in, size_t sz);
|
size_t fsendfile (FILE *out, FILE *in, size_t sz);
|
||||||
|
|
||||||
int dir (const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip);
|
int dir (const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip);
|
||||||
@@ -120,6 +120,9 @@ static inline int string_case_compare (const char *a, const char *b)
|
|||||||
return strlen (a) == strlen (b) && !strcasecmp (a, b);
|
return strlen (a) == strlen (b) && !strcasecmp (a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compat */
|
||||||
|
#define copy_filep(src, dst) fcopyfile(src,dst);
|
||||||
|
|
||||||
#endif /* FINIT_LITE_H_ */
|
#endif /* FINIT_LITE_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in new issue
Block a user