libmisc/copydir.c cleanup
* libmisc/copydir.c: Split copy_tree() in more maintainable functions: copy_entry(), copy_dir(), copy_symlink(), copy_hardlink(), copy_special(), and copy_file(). * libmisc/copydir.c: -1 is used to indicate an error, directly set err to -1, instead of incrementing it, and checking if not nul at the end.
This commit is contained in:
parent
bfa8ef3e75
commit
dfb6416a5b
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
|||||||
|
2007-12-27 Nicolas François <nicolas.francois@centraliens.net>
|
||||||
|
|
||||||
|
libmisc/copydir.c cleanup
|
||||||
|
* libmisc/copydir.c: Split copy_tree() in more maintainable functions:
|
||||||
|
copy_entry(), copy_dir(), copy_symlink(), copy_hardlink(),
|
||||||
|
copy_special(), and copy_file().
|
||||||
|
* libmisc/copydir.c: -1 is used to indicate an error, directly set err
|
||||||
|
to -1, instead of incrementing it, and checking if not nul at the
|
||||||
|
end.
|
||||||
|
|
||||||
2007-12-27 Nicolas François <nicolas.francois@centraliens.net>
|
2007-12-27 Nicolas François <nicolas.francois@centraliens.net>
|
||||||
|
|
||||||
gpasswd cleanup
|
gpasswd cleanup
|
||||||
|
@ -54,6 +54,25 @@ struct link_name {
|
|||||||
};
|
};
|
||||||
static struct link_name *links;
|
static struct link_name *links;
|
||||||
|
|
||||||
|
static int copy_entry (const char *src, const char *dst,
|
||||||
|
uid_t uid, gid_t gid);
|
||||||
|
static int copy_dir (const char *src, const char *dst,
|
||||||
|
const struct stat *statp, const struct timeval mt[2],
|
||||||
|
uid_t uid, gid_t gid);
|
||||||
|
#ifdef S_IFLNK
|
||||||
|
static int copy_symlink (const char *src, const char *dst,
|
||||||
|
const struct stat *statp, const struct timeval mt[2],
|
||||||
|
uid_t uid, gid_t gid);
|
||||||
|
#endif
|
||||||
|
static int copy_hardlink (const char *src, const char *dst,
|
||||||
|
struct link_name *lp);
|
||||||
|
static int copy_special (const char *src, const char *dst,
|
||||||
|
const struct stat *statp, const struct timeval mt[2],
|
||||||
|
uid_t uid, gid_t gid);
|
||||||
|
static int copy_file (const char *src, const char *dst,
|
||||||
|
const struct stat *statp, const struct timeval mt[2],
|
||||||
|
uid_t uid, gid_t gid);
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
static int selinux_file_context (const char *dst_name)
|
static int selinux_file_context (const char *dst_name)
|
||||||
{
|
{
|
||||||
@ -77,7 +96,6 @@ static int selinux_file_context (const char *dst_name)
|
|||||||
/*
|
/*
|
||||||
* remove_link - delete a link from the link list
|
* remove_link - delete a link from the link list
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void remove_link (struct link_name *ln)
|
static void remove_link (struct link_name *ln)
|
||||||
{
|
{
|
||||||
struct link_name *lp;
|
struct link_name *lp;
|
||||||
@ -146,16 +164,9 @@ int copy_tree (const char *src_root, const char *dst_root, uid_t uid, gid_t gid)
|
|||||||
{
|
{
|
||||||
char src_name[1024];
|
char src_name[1024];
|
||||||
char dst_name[1024];
|
char dst_name[1024];
|
||||||
char buf[1024];
|
|
||||||
int ifd;
|
|
||||||
int ofd;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int cnt;
|
|
||||||
int set_orig = 0;
|
int set_orig = 0;
|
||||||
struct DIRECT *ent;
|
struct DIRECT *ent;
|
||||||
struct stat sb;
|
|
||||||
struct link_name *lp;
|
|
||||||
struct timeval mt[2];
|
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -200,7 +211,7 @@ int copy_tree (const char *src_root, const char *dst_root, uid_t uid, gid_t gid)
|
|||||||
|
|
||||||
if (strlen (src_root) + strlen (ent->d_name) + 2 >
|
if (strlen (src_root) + strlen (ent->d_name) + 2 >
|
||||||
sizeof src_name) {
|
sizeof src_name) {
|
||||||
err++;
|
err = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
snprintf (src_name, sizeof src_name, "%s/%s", src_root,
|
snprintf (src_name, sizeof src_name, "%s/%s", src_root,
|
||||||
@ -208,15 +219,34 @@ int copy_tree (const char *src_root, const char *dst_root, uid_t uid, gid_t gid)
|
|||||||
|
|
||||||
if (strlen (dst_root) + strlen (ent->d_name) + 2 >
|
if (strlen (dst_root) + strlen (ent->d_name) + 2 >
|
||||||
sizeof dst_name) {
|
sizeof dst_name) {
|
||||||
err++;
|
err = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
snprintf (dst_name, sizeof dst_name, "%s/%s", dst_root,
|
snprintf (dst_name, sizeof dst_name, "%s/%s", dst_root,
|
||||||
ent->d_name);
|
ent->d_name);
|
||||||
|
|
||||||
if (LSTAT (src_name, &sb) == -1)
|
err = copy_entry (src_name, dst_name, uid, gid);
|
||||||
continue;
|
}
|
||||||
|
closedir (dir);
|
||||||
|
|
||||||
|
if (set_orig) {
|
||||||
|
src_orig = 0;
|
||||||
|
dst_orig = 0;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int copy_entry (const char *src, const char *dst,
|
||||||
|
uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
struct stat sb;
|
||||||
|
struct link_name *lp;
|
||||||
|
struct timeval mt[2];
|
||||||
|
|
||||||
|
if (LSTAT (src, &sb) == -1) {
|
||||||
|
/* If we cannot stat the file, do not care. */
|
||||||
|
} else {
|
||||||
#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
|
#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
|
||||||
mt[0].tv_sec = sb.st_atim.tv_sec;
|
mt[0].tv_sec = sb.st_atim.tv_sec;
|
||||||
mt[0].tv_usec = sb.st_atim.tv_nsec / 1000;
|
mt[0].tv_usec = sb.st_atim.tv_nsec / 1000;
|
||||||
@ -230,6 +260,55 @@ int copy_tree (const char *src_root, const char *dst_root, uid_t uid, gid_t gid)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (S_ISDIR (sb.st_mode)) {
|
if (S_ISDIR (sb.st_mode)) {
|
||||||
|
err = copy_dir (src, dst, &sb, mt, uid, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef S_IFLNK
|
||||||
|
/*
|
||||||
|
* Copy any symbolic links
|
||||||
|
*/
|
||||||
|
|
||||||
|
else if (S_ISLNK (sb.st_mode)) {
|
||||||
|
err = copy_symlink (src, dst, &sb, mt, uid, gid);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if this is a previously copied link
|
||||||
|
*/
|
||||||
|
|
||||||
|
else if ((lp = check_link (src, &sb))) {
|
||||||
|
err = copy_hardlink (src, dst, lp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deal with FIFOs and special files. The user really
|
||||||
|
* shouldn't have any of these, but it seems like it
|
||||||
|
* would be nice to copy everything ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
else if (!S_ISREG (sb.st_mode)) {
|
||||||
|
err = copy_special (src, dst, &sb, mt, uid, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the new file and copy the contents. The new
|
||||||
|
* file will be owned by the provided UID and GID values.
|
||||||
|
*/
|
||||||
|
|
||||||
|
else {
|
||||||
|
err = copy_file (src, dst, &sb, mt, uid, gid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int copy_dir (const char *src, const char *dst,
|
||||||
|
const struct stat *statp, const struct timeval mt[2],
|
||||||
|
uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new target directory, make it owned by
|
* Create a new target directory, make it owned by
|
||||||
@ -237,44 +316,43 @@ int copy_tree (const char *src_root, const char *dst_root, uid_t uid, gid_t gid)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
selinux_file_context (dst_name);
|
selinux_file_context (dst);
|
||||||
#endif
|
#endif
|
||||||
if (mkdir (dst_name, sb.st_mode)
|
if (mkdir (dst, statp->st_mode)
|
||||||
|| chown (dst_name,
|
|| chown (dst,
|
||||||
uid == (uid_t) - 1 ? sb.st_uid : uid,
|
uid == (uid_t) - 1 ? statp->st_uid : uid,
|
||||||
gid == (gid_t) - 1 ? sb.st_gid : gid)
|
gid == (gid_t) - 1 ? statp->st_gid : gid)
|
||||||
|| chmod (dst_name, sb.st_mode)
|
|| chmod (dst, statp->st_mode)
|
||||||
|| copy_tree (src_name, dst_name, uid, gid)
|
|| copy_tree (src, dst, uid, gid)
|
||||||
|| utimes (dst_name, mt)) {
|
|| utimes (dst, mt)) {
|
||||||
err++;
|
err = -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef S_IFLNK
|
#ifdef S_IFLNK
|
||||||
/*
|
static int copy_symlink (const char *src, const char *dst,
|
||||||
* Copy any symbolic links
|
const struct stat *statp, const struct timeval mt[2],
|
||||||
*/
|
uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
if (S_ISLNK (sb.st_mode)) {
|
|
||||||
char oldlink[1024];
|
char oldlink[1024];
|
||||||
char dummy[1024];
|
char dummy[1024];
|
||||||
int len;
|
int len;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the name of the file which the link points
|
* Get the name of the file which the link points
|
||||||
* to. If that name begins with the original
|
* to. If that name begins with the original
|
||||||
* source directory name, that part of the link
|
* source directory name, that part of the link
|
||||||
* name will be replaced with the original
|
* name will be replaced with the original
|
||||||
* destinateion directory name.
|
* destination directory name.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((len =
|
if ((len =
|
||||||
readlink (src_name, oldlink,
|
readlink (src, oldlink,
|
||||||
sizeof (oldlink) - 1)) < 0) {
|
sizeof (oldlink) - 1)) < 0) {
|
||||||
err++;
|
return -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
oldlink[len] = '\0'; /* readlink() does not NUL-terminate */
|
oldlink[len] = '\0'; /* readlink() does not NUL-terminate */
|
||||||
if (!strncmp (oldlink, src_orig, strlen (src_orig))) {
|
if (!strncmp (oldlink, src_orig, strlen (src_orig))) {
|
||||||
@ -284,14 +362,13 @@ int copy_tree (const char *src_root, const char *dst_root, uid_t uid, gid_t gid)
|
|||||||
strcpy (oldlink, dummy);
|
strcpy (oldlink, dummy);
|
||||||
}
|
}
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
selinux_file_context (dst_name);
|
selinux_file_context (dst);
|
||||||
#endif
|
#endif
|
||||||
if (symlink (oldlink, dst_name)
|
if (symlink (oldlink, dst)
|
||||||
|| lchown (dst_name,
|
|| lchown (dst,
|
||||||
uid == (uid_t) - 1 ? sb.st_uid : uid,
|
uid == (uid_t) - 1 ? statp->st_uid : uid,
|
||||||
gid == (gid_t) - 1 ? sb.st_gid : gid)) {
|
gid == (gid_t) - 1 ? statp->st_gid : gid)) {
|
||||||
err++;
|
return -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2007-10-18: We don't care about
|
/* 2007-10-18: We don't care about
|
||||||
@ -299,108 +376,94 @@ int copy_tree (const char *src_root, const char *dst_root, uid_t uid, gid_t gid)
|
|||||||
* it returns ENOSYS on many system
|
* it returns ENOSYS on many system
|
||||||
* - not implemented
|
* - not implemented
|
||||||
*/
|
*/
|
||||||
lutimes (dst_name, mt);
|
lutimes (dst, mt);
|
||||||
|
|
||||||
continue;
|
return err;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
static int copy_hardlink (const char *src, const char *dst,
|
||||||
* See if this is a previously copied link
|
struct link_name *lp)
|
||||||
*/
|
{
|
||||||
|
/* TODO: selinux needed? */
|
||||||
|
|
||||||
if ((lp = check_link (src_name, &sb))) {
|
if (link (lp->ln_name, dst)) {
|
||||||
if (link (lp->ln_name, dst_name)) {
|
return -1;
|
||||||
err++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (unlink (src_name)) {
|
if (unlink (src)) {
|
||||||
err++;
|
return -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (--lp->ln_count <= 0)
|
if (--lp->ln_count <= 0)
|
||||||
remove_link (lp);
|
remove_link (lp);
|
||||||
|
|
||||||
continue;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int copy_special (const char *src, const char *dst,
|
||||||
* Deal with FIFOs and special files. The user really
|
const struct stat *statp, const struct timeval mt[2],
|
||||||
* shouldn't have any of these, but it seems like it
|
uid_t uid, gid_t gid)
|
||||||
* would be nice to copy everything ...
|
{
|
||||||
*/
|
int err = 0;
|
||||||
|
|
||||||
if (!S_ISREG (sb.st_mode)) {
|
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
selinux_file_context (dst_name);
|
selinux_file_context (dst);
|
||||||
#endif
|
#endif
|
||||||
if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev)
|
|
||||||
|| chown (dst_name,
|
if (mknod (dst, statp->st_mode & ~07777, statp->st_rdev)
|
||||||
uid == (uid_t) - 1 ? sb.st_uid : uid,
|
|| chown (dst,
|
||||||
gid == (gid_t) - 1 ? sb.st_gid : gid)
|
uid == (uid_t) - 1 ? statp->st_uid : uid,
|
||||||
|| chmod (dst_name, sb.st_mode & 07777)
|
gid == (gid_t) - 1 ? statp->st_gid : gid)
|
||||||
|| utimes (dst_name, mt)) {
|
|| chmod (dst, statp->st_mode & 07777)
|
||||||
err++;
|
|| utimes (dst, mt)) {
|
||||||
break;
|
err = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int copy_file (const char *src, const char *dst,
|
||||||
* Create the new file and copy the contents. The new
|
const struct stat *statp, const struct timeval mt[2],
|
||||||
* file will be owned by the provided UID and GID values.
|
uid_t uid, gid_t gid)
|
||||||
*/
|
{
|
||||||
|
int err = 0;
|
||||||
|
int ifd;
|
||||||
|
int ofd;
|
||||||
|
char buf[1024];
|
||||||
|
int cnt;
|
||||||
|
|
||||||
if ((ifd = open (src_name, O_RDONLY)) < 0) {
|
if ((ifd = open (src, O_RDONLY)) < 0) {
|
||||||
err++;
|
return -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
selinux_file_context (dst_name);
|
selinux_file_context (dst);
|
||||||
#endif
|
#endif
|
||||||
if ((ofd =
|
if ((ofd =
|
||||||
open (dst_name, O_WRONLY | O_CREAT | O_TRUNC, 0)) < 0
|
open (dst, O_WRONLY | O_CREAT | O_TRUNC, 0)) < 0
|
||||||
|| chown (dst_name,
|
|| chown (dst,
|
||||||
uid == (uid_t) - 1 ? sb.st_uid : uid,
|
uid == (uid_t) - 1 ? statp->st_uid : uid,
|
||||||
gid == (gid_t) - 1 ? sb.st_gid : gid)
|
gid == (gid_t) - 1 ? statp->st_gid : gid)
|
||||||
|| chmod (dst_name, sb.st_mode & 07777)) {
|
|| chmod (dst, statp->st_mode & 07777)) {
|
||||||
close (ifd);
|
close (ifd);
|
||||||
err++;
|
return -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
|
while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
|
||||||
if (write (ofd, buf, cnt) != cnt) {
|
if (write (ofd, buf, cnt) != cnt) {
|
||||||
cnt = -1;
|
return -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close (ifd);
|
close (ifd);
|
||||||
|
|
||||||
if (futimes (ofd, mt) != 0) {
|
if (futimes (ofd, mt) != 0) {
|
||||||
err++;
|
return -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (close (ofd) != 0) {
|
if (close (ofd) != 0) {
|
||||||
err++;
|
return -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cnt == -1) {
|
return err;
|
||||||
err++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir (dir);
|
|
||||||
|
|
||||||
if (set_orig) {
|
|
||||||
src_orig = 0;
|
|
||||||
dst_orig = 0;
|
|
||||||
}
|
|
||||||
return err ? -1 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -451,7 +514,7 @@ int remove_tree (const char *root)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) {
|
if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) {
|
||||||
err++;
|
err = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
snprintf (new_name, sizeof new_name, "%s/%s", root,
|
snprintf (new_name, sizeof new_name, "%s/%s", root,
|
||||||
@ -466,11 +529,11 @@ int remove_tree (const char *root)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (remove_tree (new_name)) {
|
if (remove_tree (new_name)) {
|
||||||
err++;
|
err = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (rmdir (new_name)) {
|
if (rmdir (new_name)) {
|
||||||
err++;
|
err = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -479,5 +542,5 @@ int remove_tree (const char *root)
|
|||||||
}
|
}
|
||||||
closedir (dir);
|
closedir (dir);
|
||||||
|
|
||||||
return err ? -1 : 0;
|
return err;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user