c ++ implementation file copy and modify the appropriate property

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

  1. int lstat(const char *pathname, struct stat *statbuf);

    • const char *pathname You need to determine the path of the file
    • struct stat *statbuf To save the file attributes
    • return int 0 successful -1 Failure
  2. 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

  1. DIR *opendir(const char *name);

    • const char *name Directory path to be opened
    • return DIR Back to Contents data structure
  2. struct dirent *readdir(DIR *dirp);

    • `` ` DIR *dirpTo be read directory

    • return struct dirent* Back to directory entries in the directory read sequentially

      Note that the first item is a directory ., the second directory entry is..

Copy files

  1. int open(const char *pathname, int flags, mode_t mode);
    • const char* pathname The file path to be opened
    • int flags O_RDONLY, O_WRONLY, or O_RDWR
    • mode_t mode
    • return int The return value is an open file descriptor
  2. 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 property
    • return int File descriptors to be created
  3. ssize_t read(int fd, void *buf, size_t count);
    • int fd File descriptor to be read
    • void* bufRead the contents of the storage buffer. While there is void*, bufat the time of creation should be `` `char *` `` `` `
    • `` ` size_t countContent to be read size. If more than fdthe number of, the size of the content read the corresponding
    • return ssize_tReturns the content actually read the number. Failure to return -1
  4. ssize_t write(int fd, const void *buf, size_t count);
    • int fd File descriptor to be written
    • const void *buf To write the contents of.
    • size_t count Size of the content to be written
    • return ssize_tSuccessful return number actually written. Failure to return -1

Copy the folder

Copy the folder is to create a folder with the same name

  1. int mkdir(const char *pathname, mode_t mode);
    • const char* pathname Address directory entries to be created
    • mode_t mode Create a directory entry attributes
    • return int If successful return 0, otherwise -1

Copy soft links

  1. ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
    • const cha* pathname To be read soft link path
    • char* bufSave content soft links to bufthe
    • size_t bufsiz bufBuffer size
    • return ssize_t The return value is the length of the flexible link to the path
  2. int symlink(const char *target, const char *linkpath);
    • const char* target Soft link path to be created
    • const char* linkpath Soft link to be created in the path pointed to
    • return int Successful return 0, otherwise -1

Acquiring property

  1. int lstat(const char *pathname, struct stat *statbuf);

    • const char *pathname Path need to extract the properties of a file or folder
    • struct stat *statbuf Acquired attribute memory buffer
    • return int Successful return 0, otherwise -1
  2. int chmod(const char *pathname, mode_t mode);

    • const char *pathname Path of the file to be modified property
    • mode_t mode Modify the file will be changed to modify this property
    • return int If successful return 0, otherwise -1
  3. int chown(const char *pathname, uid_t owner, gid_t group);

    • const char* pathname Change the directory path to be
    • uid_t owner If the property is not changed -1
    • gid_t group If the property is not changed -1
  4. int lutimes(const char *filename, const struct timeval tv[2]);

    This command is used to modify the target file access_time modify_time. lutimesYou can modify the properties of soft links.

    • const char *filename The file path to be modified
    • const struct timeval tv[2] tv[0]Shi access_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;
}

Guess you like

Origin www.cnblogs.com/harrypotterjackson/p/12041311.html