Problem Description
A complete directory replication command mycp, including files and subdirectories, the results are as follows:
[email protected] [~/]# ls –la sem
total 56
drwxr-xr-x 3 beta beta 4096 Dec 19 02:53 ./
drwxr-xr-x 8 beta beta 4096 Nov 27 08:49 ../
-rw-r--r-- 1 beta beta 128 Nov 27 09:31 Makefile
-rwxr-xr-x 1 beta beta 5705 Nov 27 08:50 consumer*
-rw-r--r-- 1 beta beta 349 Nov 27 09:30 consumer.c
drwxr-xr-x 2 beta beta 4096 Dec 19 02:53 subdir/
[email protected] [~/]# mycp sem target
[email protected] [~/]# ls –la target
total 56
drwxr-xr-x 3 beta beta 4096 Dec 19 02:53 ./
drwxr-xr-x 8 beta beta 4096 Nov 27 08:49 ../
-rw-r--r-- 1 beta beta 128 Nov 27 09:31 Makefile
-rwxr-xr-x 1 beta beta 5705 Nov 27 08:50 consumer*
-rw-r--r-- 1 beta beta 349 Nov 27 09:30 consumer.c
drwxr-xr-x 2 beta beta 4096 Dec 19 02:53 subdir/
Thinking
This question is mainly related to reading and writing files and attribute modification. The need to support folder, file copy, but to support replication soft link under Linux.
Ideas are as follows:
- Gets the absolute path of the directory to be copied
- Dfs carried out according to the absolute path or bfs search all subdirectories items
- Is to determine what type of subdirectories: folders, ordinary file, soft links
- Each of the three (only the folders and files under Windows) to copy operations
- Modify the target file attributes consistent with the source file
Use the functions are:
Linux
Determine the file type
int lstat(const char *pathname, struct stat *statbuf);
const char *pathname
You need to determine the path of the filestruct stat *statbuf
To save the file attributesreturn int
0 successful -1 Failure
Judge
file type Explanation Judging function example Trivial File Files in general S_ISREG() hello.c Directory files It may also contain additional files or directories S_ISDIR() /etc/ Character device file In unbuffered mode, provides access to the variable-length device S_ISCHR() /dev/tty Block device file In buffered mode, it provides access to the fixed length of the device S_ISBLK() / Dev / sda Symbolic link file Points to another file S_ISLNK() /dev/cdrom Named Pipe File For interprocess communication S_ISFIFO() /dev/inictl Network socket file Network for communication between processes S_ISSOCK() /dev/log It is noteworthy that, you need to determine is not a symbolic link file. Symbolic link file
S_ISREG()
case it is determined that the file will appear when ordinary judge. Probably because of his judgment it is the type of link file points to the file. So you need to determine is not a link file.
File directory traversal
DIR *opendir(const char *name);
const char *name
Directory path to be openedreturn DIR
Back to Contents data structure
struct dirent *readdir(DIR *dirp);
`` `
DIR *dirp
To be read directoryreturn struct dirent*
Back to directory entries in the directory read sequentiallyNote that the first item is a directory
.
, the second directory entry is..
Copy files
int open(const char *pathname, int flags, mode_t mode);
const char* pathname
The file path to be openedint flags
O_RDONLY, O_WRONLY, or O_RDWR
mode_t mode
return int
The return value is an open file descriptor
int creat(const char *pathname, mode_t mode);
const char* pathname
The file name to be created (can include path)mode_t mode
Create a propertyreturn int
File descriptors to be created
ssize_t read(int fd, void *buf, size_t count);
int fd
File descriptor to be readvoid* buf
Read the contents of the storage buffer. While there isvoid*
,buf
at the time of creation should be `` `char *` `` `` `- `` `
size_t count
Content to be read size. If more thanfd
the number of, the size of the content read the corresponding return ssize_t
Returns the content actually read the number. Failure to return -1
ssize_t write(int fd, const void *buf, size_t count);
int fd
File descriptor to be writtenconst void *buf
To write the contents of.size_t count
Size of the content to be writtenreturn ssize_t
Successful return number actually written. Failure to return -1
Copy the folder
Copy the folder is to create a folder with the same name
int mkdir(const char *pathname, mode_t mode);
const char* pathname
Address directory entries to be createdmode_t mode
Create a directory entry attributesreturn int
If successful return 0, otherwise -1
Copy soft links
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
const cha* pathname
To be read soft link pathchar* buf
Save content soft links tobuf
thesize_t bufsiz
buf
Buffer sizereturn ssize_t
The return value is the length of the flexible link to the path
int symlink(const char *target, const char *linkpath);
const char* target
Soft link path to be createdconst char* linkpath
Soft link to be created in the path pointed toreturn int
Successful return 0, otherwise -1
Acquiring property
int lstat(const char *pathname, struct stat *statbuf);
const char *pathname
Path need to extract the properties of a file or folderstruct stat *statbuf
Acquired attribute memory bufferreturn int
Successful return 0, otherwise -1
int chmod(const char *pathname, mode_t mode);
const char *pathname
Path of the file to be modified propertymode_t mode
Modify the file will be changed to modify this propertyreturn int
If successful return 0, otherwise -1
int chown(const char *pathname, uid_t owner, gid_t group);
const char* pathname
Change the directory path to beuid_t owner
If the property is not changed -1gid_t group
If the property is not changed -1
int lutimes(const char *filename, const struct timeval tv[2]);
This command is used to modify the target file
access_time
modify_time
.lutimes
You can modify the properties of soft links.const char *filename
The file path to be modifiedconst struct timeval tv[2]
tv[0]
Shiaccess_time
,tv[1]
Shimodify_time
return int
If successful return 0, otherwise -1
Windows
Here are listed main function used, there is a need, then you can go check the relevant detailed description of the function:
FindFirstFile
FindNextFile
CreateFile
GetFileSize
ReadFile
WriteFile
_wmkdir
GetFileAttributes
SetFileAttributes
GetFileTime
FileTimeToSystemTime
SetFileTime
Source code implementation
Linux
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <utime.h>
#include <time.h>
#include <sys/time.h>
//文件夹复制采用dfs或者bfs进行搜索是等价的
void search_dfs(char *src_path, char *dest_path);
//复制文件
void copy_file(const char *src_file, const char *dst_file);
//复制文件夹
void copy_dir(const char *src_dir, const char *dst_dir);
//复制软链接
void copy_sln(const char *src_file, const char *dst_file);
//修改文件属性与源文件保持一致
void changeAttr(const char *src, const char *dst);
//修改路径
void change_path(char *src, char *cat)
{
strcat(src, (char *)"/");
strcat(src, cat);
}
int main(int argc, char const *argv[])
{
if (argc < 3)
{
printf("No file or directory specified\n");
exit(-1);
}
if (argc > 3)
{
printf("Too many arguments\n");
exit(-1);
}
char src[1024], dest[1024];
char *current_dir = getcwd(NULL, 0);
struct stat state_of_entry;
lstat(argv[1], &state_of_entry);
if (S_ISDIR(state_of_entry.st_mode)) //目录
{
if (chdir(argv[1])) //目录错误
{
perror("chdir");
exit(-1);
}
strcpy(src, getcwd(NULL, 0)); //获取源文件夹绝对路径
chdir(current_dir);
lstat(argv[2], &state_of_entry);
if (S_ISDIR(state_of_entry.st_mode)) //目录
{
if (chdir(argv[2])) //目录错误
{
perror("chdir");
exit(-1);
}
strcpy(dest, getcwd(NULL, 0)); //获取目标文件夹绝对路径
chdir(current_dir);
chdir(dest);
// printf("SRC: %s\n", src);
// printf("DEST: %s\n", dest);
chdir(src);
search_dfs(src, dest);
}
else
{
printf("error. No destination directory.\n");
exit(-1);
}
}
else //文件直接复制
{
char dest[1024];
lstat(argv[2], &state_of_entry);
if (S_ISDIR(state_of_entry.st_mode)) //目录
{
strcpy(dest, getcwd(NULL, 0)); //获取目标文件夹绝对路径
}
else
{
strcpy(dest, "./");
strcat(dest, argv[2]);
}
copy_file(argv[1], argv[2]);
}
return 0;
}
void search_dfs(char *src_path, char *dest_path)
{
// printf("Searching directory: %s\n", getcwd(NULL, 0));
DIR *src_dir = opendir(src_path);
DIR *dest_dir = opendir(dest_path);
struct dirent *entry = NULL;
struct stat state_of_entry;
while ((entry = readdir(src_dir)) != NULL)
{
lstat(entry->d_name, &state_of_entry);
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// printf("entry->d_name: %s\n", entry->d_name);
if (S_ISLNK(state_of_entry.st_mode)) //符号链接
{
char src_file[1024];
char dest_file[1024];
strcpy(src_file, src_path);
change_path(src_file, entry->d_name);
strcpy(dest_file, dest_path);
change_path(dest_file, entry->d_name);
// printf("src file: %s\n", src_file);
// printf("dest file: %s\n", dest_file);
copy_sln(src_file, dest_file);
}
else if (S_ISREG(state_of_entry.st_mode)) //普通文件
{
char src_file[1024];
char dest_file[1024];
strcpy(src_file, src_path);
change_path(src_file, entry->d_name);
strcpy(dest_file, dest_path);
change_path(dest_file, entry->d_name);
// printf("src file: %s\n", src_file);
// printf("dest file: %s\n", dest_file);
copy_file(src_file, dest_file);
}
else if (S_ISDIR(state_of_entry.st_mode)) //目录
{
char src[1024];
char dest[1024];
strcpy(src, src_path);
change_path(src, entry->d_name);
strcpy(dest, dest_path);
change_path(dest, entry->d_name);
// printf("src dir: %s\n", src);
// printf("dest dir: %s\n", dest);
copy_dir(src, dest);
search_dfs(src, dest);
}
}
}
void copy_file(const char *src_file, const char *dest_file)
{
int src_fd = open(src_file, O_RDONLY);
int dest_fd = creat(dest_file, O_WRONLY);
unsigned char buf[1024];
while (read(src_fd, buf, sizeof(buf)) > 0)
{
write(dest_fd, buf, sizeof(buf));
}
changeAttr(src_file, dest_file);
close(src_fd);
close(dest_fd);
}
void copy_dir(const char *src_dir, const char *dst_dir)
{
mkdir(dst_dir, 0777);
changeAttr(src_dir, dst_dir);
}
void copy_sln(const char *src_file, const char *dst_file)
{
char buf[1024];
memset(buf, 0, sizeof(buf));
int len = 0;
if ((len = readlink(src_file, buf, sizeof(buf))) > 0)
{
printf("%s\n", buf);
if (symlink(buf, dst_file) == -1)
{
perror("symlink");
}
}
changeAttr(src_file, dst_file);
}
void changeAttr(const char *src, const char *dst)
{
struct stat attr_of_src;
lstat(src, &attr_of_src);
//修改文件属性
chmod(dst, attr_of_src.st_mode);
//修改文件用户组
chown(dst, attr_of_src.st_uid, attr_of_src.st_gid);
//修改文件访问、修改时间
struct timeval time_buf[2];
time_buf[1].tv_sec = attr_of_src.st_mtime;
time_buf[0].tv_sec = attr_of_src.st_atime;
if(lutimes(dst, time_buf) == -1)
{
printf("%s\n", dst);
perror("lutimes");
}
struct utimbuf tbuf;
tbuf.actime = attr_of_src.st_atime;
tbuf.modtime = attr_of_src.st_mtime;
utime(dst, &tbuf);
struct stat dst_attr_of_src;
lstat(dst, &dst_attr_of_src);
if (dst_attr_of_src.st_mtime != attr_of_src.st_mtime)
printf("%s : %d\n", dst, attr_of_src.st_mtime);
}
Windows
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
#include <cstring>
#define BUF_SIZE 1024
using namespace std;
//文件夹复制采用dfs或者bfs进行搜索是等价的
void search_dfs(wchar_t* src_path, wchar_t* dest_path);
//复制文件
void copy_file(const wchar_t* src_file, const wchar_t* dst_file);
//复制文件夹
void copy_dir(const wchar_t* src_dir, const wchar_t* dst_dir);
//修改文件属性与源文件保持一致
void change_attr(const wchar_t* src_name, const wchar_t* dst_name, HANDLE h_src, HANDLE h_dst);
int wmain(int argc, wchar_t* argv[])
{
setlocale(LC_ALL, "");
wchar_t* src_path = new wchar_t[BUF_SIZE];
wchar_t* dst_path = new wchar_t[BUF_SIZE];
ZeroMemory(src_path, BUF_SIZE);
ZeroMemory(dst_path, BUF_SIZE);
wcscpy(src_path, argv[1]);
wcscat(src_path, L"\\*");
wcscpy(dst_path, argv[2]);
wcout << L"src_path" << src_path << endl;
wcout << L"dst_path" << dst_path << endl;
//wcscpy(src_path, L"E:\\薪火培训\\*");
//wcscpy(dst_path, L"E:\\2333");
search_dfs(src_path, dst_path);
delete[] src_path;
delete[] dst_path;
return 0;
}
//复制文件
void copy_file(const wchar_t* src_file, const wchar_t* dst_file)
{
HANDLE h_src = ::CreateFile(
src_file,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
NULL);
HANDLE h_dst = ::CreateFile(
dst_file,
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (h_src == INVALID_HANDLE_VALUE || h_dst == INVALID_HANDLE_VALUE)
{
printf("Open file error!\n");
CloseHandle(h_src);
CloseHandle(h_dst);
exit(-1);
}
DWORD all_bytes = GetFileSize(h_src, NULL);
char* buffer = new char[all_bytes + 1];
ZeroMemory(buffer, all_bytes + 1);
DWORD bytes = 0;
ReadFile(h_src, buffer, all_bytes, &bytes, NULL);
WriteFile(h_dst, buffer, all_bytes, &bytes, NULL);
change_attr(src_file, dst_file, h_src, h_dst);
CloseHandle(h_src);
CloseHandle(h_dst);
delete[] buffer;
return;
}
//复制文件夹
void copy_dir(const wchar_t* src_dirr, const wchar_t* dst_dir)
{
wchar_t* src_dir = new wchar_t[BUF_SIZE];
wcscpy(src_dir, src_dirr);
src_dir[wcslen(src_dir) - 2] = '\0';
_wmkdir(dst_dir);
HANDLE h_src = CreateFile(
src_dir,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL
);
if (h_src == INVALID_HANDLE_VALUE)
{
printf("Open src directory error!\n");
CloseHandle(h_src);
exit(-1);
}
HANDLE h_dst = CreateFile(
dst_dir,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL
);
if (h_dst == INVALID_HANDLE_VALUE)
{
printf("Open dst directory error!\n");
CloseHandle(h_dst);
exit(-1);
}
change_attr(src_dir, dst_dir, h_src, h_dst);
CloseHandle(h_src);
CloseHandle(h_dst);
return;
}
void search_dfs(wchar_t* src_path, wchar_t* dst_path)
{
HANDLE h_find;
WIN32_FIND_DATA find_data;
LARGE_INTEGER size;
h_find = FindFirstFile(src_path, &find_data);
if (h_find == INVALID_HANDLE_VALUE)
{
cout << "Fail to find first file" << endl;
return;
}
copy_dir(src_path, dst_path);
do
{
wcout << find_data.cFileName << endl;
if (wcscmp(find_data.cFileName, L".") == 0 || wcscmp(find_data.cFileName, L"..") == 0)
{
continue;
}
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)//是目录
{
wchar_t n_src_path[BUF_SIZE];
wcscpy(n_src_path, src_path);
n_src_path[wcslen(n_src_path) - 1] = '\0';
wcscat(n_src_path, find_data.cFileName);
wcscat(n_src_path, L"\\*");
wchar_t n_dst_path[BUF_SIZE];
wcscpy(n_dst_path, dst_path);
wcscat(n_dst_path, L"\\");
wcscat(n_dst_path, find_data.cFileName);
copy_dir(n_src_path, n_dst_path);
search_dfs(n_src_path, n_dst_path);
}
else
{
//size.LowPart = find_data.nFileSizeLow;
//size.HighPart = find_data.nFileSizeHigh;
//wcout << find_data.cFileName << "\t" << size.QuadPart << " bytes" << endl;
wchar_t n_src_path[BUF_SIZE];
wcscpy(n_src_path, src_path);
n_src_path[wcslen(n_src_path) - 1] = '\0';
wcscat(n_src_path, find_data.cFileName);
wchar_t n_dst_path[BUF_SIZE];
wcscpy(n_dst_path, dst_path);
wcscat(n_dst_path, L"\\");
wcscat(n_dst_path, find_data.cFileName);
copy_file(n_src_path, n_dst_path);
}
} while (FindNextFile(h_find, &find_data));
return;
}
//修改文件属性与源文件保持一致
void change_attr(const wchar_t* src_name, const wchar_t* dst_name, HANDLE h_src, HANDLE h_dst)
{
DWORD attr = GetFileAttributes(src_name);
SetFileAttributes(dst_name, attr);
FILETIME t_create, t_access, t_write;
SYSTEMTIME syst_create, syst_access, syst_write;
GetFileTime(h_src, &t_create, &t_access, &t_write);
FileTimeToSystemTime(&t_create, &syst_create);
//cout << syst_create.wDay << endl;
SetFileTime(h_dst, &t_create, &t_access, &t_write);
GetFileTime(h_dst, &t_create, &t_access, &t_write);
FileTimeToSystemTime(&t_create, &syst_create);
//cout << syst_create.wDay << endl;
}