1. 程式人生 > >C語言編寫Copy程式(Linux環境下的操作)

C語言編寫Copy程式(Linux環境下的操作)

COPY程式的編寫

(作者:Baron_wu 禁止轉載)

一、實驗描述

在這個實驗中,我們要做一個程式,這個程式是將一個檔案的內容複製到一個目標檔案。首先這個程式提示使用者輸入要複製的原始檔案的名字,以及要複製到的目標檔案的名字。
確保包括必要的錯誤檢查,包括確保原始檔案存在。再使用程式的同時我們要監視這個過程中所用到的系統呼叫。Linux可使用strace來完成。

二、相關原理與知識

(完成實驗所用到的相關原理與知識)
系統呼叫的工作方式:
一般的,程序是不能訪問核心的。它不能訪問核心所佔記憶體空間也不能呼叫核心函式。CPU硬體決定了這些(這就是為什麼它被稱作"保護模式")。系統呼叫是這些規則的一個例外。其原理是程序先用適當的值填充暫存器,然後呼叫一個特殊的指令,這個指令會跳到一個事先定義的核心中的一個位置(當然,這個位置是使用者程序可讀但是不可寫的)。在Intel CPU中,這個由中斷0x80實現。硬體知道一旦你跳到這個位置,你就不是在限制模式下執行的使用者,而是作為作業系統的核心–所以你就可以為所欲為。
程序可以跳轉到的核心位置叫做sysem_call。這個過程檢查系統呼叫號,這個號碼告訴核心程序請求哪種服務。然後,它檢視系統呼叫表(sys_call_table)找到所呼叫的核心函式入口地址。接著,就呼叫函式,等返回後,做一些系統檢查,最後返回到程序(或到其他程序,如果這個程序時間用盡)。如果你希望讀這段程式碼,它在==<核心原始碼目錄>/kernel/entry.S,Entry(system_call)==的下一行。

圖為執行過程中使用者模式到核心模式的一個open函式的呼叫。
在這裡插入圖片描述

圖為引數存在記憶體的圖和表中,並將塊的地址通過暫存器來傳遞。
在這裡插入圖片描述

圖為c程式在呼叫printf時,c程式庫攔截這個呼叫來呼叫必要的作業系統呼叫write()。然後c程式再將write的返回值返回給使用者。
在這裡插入圖片描述

三、實驗過程

(實際操作過程,相關截圖及解釋)

  1. 建立一個copy.c檔案,寫入程式碼
    在這裡插入圖片描述
    在這裡插入圖片描述

  2. 寫入的複製檔案的程式碼(一種方式為使用者在執行程式時就傳入引數,另一種方式為互動式讓使用者輸入引數<註釋掉的程式碼>。)

  3. 編譯寫好的copy.c檔案
    在這裡插入圖片描述

  • strace 顯示這些呼叫的引數並返回符號形式的值。strace 從核心接收資訊,而且不需要以任何特殊的方式來構建核心。-o
    xxx.txt 輸出到某個檔案。./copy即為執行copy。
    在這裡插入圖片描述

檢視複製後的檔案的內容
在這裡插入圖片描述

  • 利用ls檢視所有生成的檔案,即由strace生成的copy.txt檔案以及複製後得到的copy1.c檔案
    在這裡插入圖片描述
  • 檢視生成的copy.txt檔案的內容

在這裡插入圖片描述
在這裡插入圖片描述

  • 輸入strace -c ./copy來獲取複製過程中所呼叫的系統函式,可以看到此過程中呼叫的read、write、open、close…等函式。
    在這裡插入圖片描述
  • 實驗分析:根據指令strace -c ./copy可以看到在檔案複製過程中使用了檔案系統控制系統呼叫。
read:讀檔案
write:寫檔案
open:開啟檔案
close:關閉檔案描述字
fstat:取檔案狀態資訊
lseek:移動檔案指標
mmap:對映虛擬記憶體頁
mprotect:設定記憶體映像保護
munmap:去除記憶體頁對映
brk:改變資料段空間的分配
access:確定檔案的可存取性
execve:執行可執行檔案
arch_prctl:  函式設定架構的具體程序或執行緒狀態

原始碼

(源程式)c程式原始碼


    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    int main(int argc,char *argv[])
    {
        FILE * fin;
        FILE * fout;
        int ch;
        char *f_read = argv[1];
        char *f_write = argv[2];
        // printf("input the file :");
        // scanf("%s",f_read);
        // printf("input the new file name :");
        // scanf("%s",f_write);
        
        fin = fopen(f_read,"rb");
        fout = fopen(f_write,"wb");
        ch = getc(fin);
        while(ch != EOF)
        {
          putc(ch,fout);
          ch = getc(fin);
        }
        return 0;
        
    }

執行程式的指令:

  1. vim copy.c開啟copy.c並進行編輯
  2. gcc -o copy copy.c編譯copy.c生成copy程式
  3. ./copy執行copy程式
  4. cat copy1.c檢視複製後的檔案copy.txt的內容
  5. strace -o copy.txt ./copy監視copy程式的執行,並生成一個copy.txt監視檔案
  6. strace -c ./copy檢視執行copy程式時呼叫了那些系統呼叫