a195f436b7
It solves problem with transferring r.x directory. Originally, it would fail when creating files in the directory (as it is not writable). Now, we will create it rwx, create files in it, and fix perms and utimes on the second pass. [user@devel fcopy]$ ls -ald /boot dr-xr-xr-x 4 root root 4096 Sep 1 2010 /boot
106 lines
2.2 KiB
C
106 lines
2.2 KiB
C
#include <errno.h>
|
|
#include <ioall.h>
|
|
#include <fcntl.h>
|
|
#include <sys/time.h>
|
|
#include <sys/stat.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include "filecopy.h"
|
|
|
|
char namebuf[MAX_PATH_LENGTH];
|
|
void notify_progress(int p1, int p2)
|
|
{
|
|
}
|
|
|
|
int global_status_fd;
|
|
void do_exit(int code)
|
|
{
|
|
int codebuf = code;
|
|
write(global_status_fd, &codebuf, sizeof codebuf);
|
|
exit(0);
|
|
}
|
|
|
|
|
|
void fix_times_and_perms(struct file_header *hdr, char *name)
|
|
{
|
|
struct timeval times[2] =
|
|
{ {hdr->atime, hdr->atime_nsec / 1000}, {hdr->mtime,
|
|
hdr->mtime_nsec / 1000}
|
|
};
|
|
if (chmod(name, hdr->mode & 07777))
|
|
do_exit(errno);
|
|
if (utimes(name, times))
|
|
do_exit(errno);
|
|
}
|
|
|
|
|
|
|
|
void process_one_file_reg(struct file_header *hdr, char *name)
|
|
{
|
|
char *ret;
|
|
int fdout =
|
|
open(name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0700);
|
|
if (fdout < 0)
|
|
do_exit(errno);
|
|
ret = copy_file(fdout, 0, hdr->filelen);
|
|
if (ret)
|
|
do_exit(errno);
|
|
close(fdout);
|
|
fix_times_and_perms(hdr, name);
|
|
}
|
|
|
|
|
|
void process_one_file_dir(struct file_header *hdr, char *name)
|
|
{
|
|
// fix perms only when the directory is sent for the second time
|
|
// it allows to transfer r.x directory contents, as we create it rwx initially
|
|
if (!mkdir(name, 0700))
|
|
return;
|
|
if (errno != EEXIST)
|
|
do_exit(errno);
|
|
fix_times_and_perms(hdr, name);
|
|
}
|
|
|
|
void process_one_file_link(struct file_header *hdr, char *name)
|
|
{
|
|
char content[MAX_PATH_LENGTH];
|
|
if (hdr->filelen > MAX_PATH_LENGTH - 1)
|
|
do_exit(ENAMETOOLONG);
|
|
if (!read_all(0, content, hdr->filelen))
|
|
do_exit(errno);
|
|
content[hdr->filelen] = 0;
|
|
if (symlink(content, name))
|
|
do_exit(errno);
|
|
|
|
}
|
|
|
|
void process_one_file(struct file_header *hdr)
|
|
{
|
|
if (hdr->namelen > MAX_PATH_LENGTH - 1)
|
|
do_exit(ENAMETOOLONG);
|
|
if (!read_all(0, namebuf, hdr->namelen))
|
|
do_exit(errno);
|
|
namebuf[hdr->namelen] = 0;
|
|
if (S_ISREG(hdr->mode))
|
|
process_one_file_reg(hdr, namebuf);
|
|
else if (S_ISLNK(hdr->mode))
|
|
process_one_file_link(hdr, namebuf);
|
|
else if (S_ISDIR(hdr->mode))
|
|
process_one_file_dir(hdr, namebuf);
|
|
else
|
|
do_exit(EINVAL);
|
|
}
|
|
|
|
void do_unpack(int fd)
|
|
{
|
|
global_status_fd = fd;
|
|
struct file_header hdr;
|
|
while (read_all(0, &hdr, sizeof hdr))
|
|
process_one_file(&hdr);
|
|
if (errno)
|
|
do_exit(errno);
|
|
else
|
|
do_exit(LEGAL_EOF);
|
|
}
|