close
系統程式作業三:實做出與UNIX下指令"cp"的類似功能

,即可複製regular file,directory,symbol link這三種檔案

(實際的cp可複製很多種格式的檔案,如socket,block special,fifo等)

執行時為:      ./mycp   XXXXX<-欲複製檔名(包含所在的絕對路徑)

這次作業的實做方法分成幾個部份:

1.取出欲複製檔案名稱

 
 ex:./mycp /moli/hw3/file    //其中file便是我們要取出的名稱
 
   我的作法是將取出名稱這動作寫成一個函式 void target_get(char TargetPath[])

 也就是把 /moli/hw3/file這個字串傳入函式 
  
 此外宣告一個global char array :TargetName[30] (這有個缺點  檔案名稱超過30 bytes就掰了...orz)

 取出方法就是每讀一個TargetPath裡的字元 就將它複製進TargetName

    遇到'/'就把TargetName的內容清空(設為'\0')重新取  當TargetPath遇到結束字元{'\0')時

 這時所存在TargetName的東西就是我們要的檔案名稱了 (directory 要多加一個'/'後面即為結束字元的判斷)

2.判斷欲複製檔案類型

 在UNIX系統裡,有內建一個名為stat的struct  裡面內容為下列型式
 
    *紅色部份代表作業中有要用到的部份

 
struct stat {
  mode_t st_mode; /* file type & mode (permissions) */ 檔案類型
  ino_t st_ino; /* i-node number (serial number) */ dev_t st_dev; /*
  device number (file system) */ dev_t st_rdev; /*
  device number for special files */
  nlink_t st_nlink; /* number of links */
  uid_t st_uid; /* user ID of owner */ User ID
  gid_t st_gid; /* group ID of owner */  group ID

  off_t st_size; /* size in bytes, for regular files */
  time_t st_atime; /* time of last access */
  time_t st_mtime; /* time of last modification */
  time_t st_ctime; /* time of last file status change */
  blksize_t st_blksize; /* best I/O block size */
  blkcnt_t st_blocks; /* number of disk blocks allocated */
 };
 所以我們必須先宣告一個有這樣struct的東西來存放我們的檔案資訊  ex:struct stat buf

   之後利用lstat這個函式還取得檔案的資訊 (複製檔案資訊還有stat,fstat可用,因作業有需要複製symlink 所以用lstat) 

   int lstat(const char *restrict pathname, struct stat *restrict buf)   
return: 0 if OK, 1 on error
 
  pathname: 檔案路徑  buf: 存放檔案的地方
 
3.依據檔案類型做複製動作

   以下的處理方式都包成一個函式mycp(char* Source,char* Target)

 lstat做完後 buf.st_mode代表的就是我們剛剛pathname裡的檔案類型
 
 之後分別用S_ISREG( ),S_ISDIR( ),S_ISLNK( )來判斷
regular file,directory,symbol link

    (i) regular file:
  
         用之前作業二的方法就ok了 但因之前沒考慮檔案大小的不確定
   
  所以buffer是用陣列來做 這是就改用動態取檔案大小的memory來做buffer

  tempbuf=(char*)malloc(Remain*sizeof(char));      //allocate the memory space we need

  其他作法都一樣
 
 (ii) symbolic link

        要複製檔案為symbol link後 我們先用readlink來得知這個link的大小)

        ssize_t readlink(const char* restrict pathname,  char *restrict buf, size_t bufsize);

        pathname:link的檔案路徑  buf :存放link資訊的buffer bufsize:buffer的大小

       要知道link的大小是因為它複製到buf的檔案資訊結尾沒有結束字元,所以我們要在buf後面加個'\0' ex:buf[linklen]='\0'

        在UNIX系統裡 我們用內建的symlink來建立起symbol link

        int symlink(const char *actualpath, const char  *sympath);
  
        actualpath: 被連結的檔案路徑   sympath:我們所要建立的symbol link路徑
 
     (iii)directory

        目錄的複製是這次作業最麻煩的地方 因為目錄裡面可能還有目錄或是其他檔案

        我們都必須把它一起複製過來   課本的方法是也是用遞迴的方式去做

        但又牽扯到i  node的方法(即由inode的數目及類型去做複製的動作) 很複雜難懂

        所以最後還是用重複呼叫mycp function的遞迴法去做

       其中檔案有它特殊的指標型態 DIR  還有存放目錄資訊的struct  dirent

       struct dirent {
                                 ino_t d_ino; /* i-node number */
                                 char d_name[NAME_MAX + 1]; /* null-terminated filename */
       }
 
 
       先利用mkdir這函式在我們的目標位置建立一個新的目錄
           
      int mkdir(const char *pathname, mode_t mode);      Returns: 0 if OK, 1 on error

     pathname: 欲建立的目錄路徑名稱      mode: 此新建目錄的權限

    建立好後 就用opendir來打開我們要複製的路徑、readdir來開始我們的遞迴複製過程
 
   DIR *opendir(const char *pathname);     Returns: pointer if OK, NULL on error

    while((dirp=readdir(dp))!=NULL){                   //一直往下層收尋
              if(strcmp(dirp->d_name,".")==0||strcmp(dirp->d_name,"..")==0) continue;   //dirp
              else {                //copy files in directory recursivly
                         strcpy(want,go);
                         for(j=0;j<30;j++) TargetName[j]='\0';
                         mycp(strcat(strcat(sourcepath,"/"),dirp->d_name),strcat(strcat(want,"/"),dirp->d_name));  //若目錄下還有東西 就在呼叫mycp去做三種檔案類型的判斷
                         strcpy(sourcepath,Source);
                      }
    }

當複製完成後 我們必須讓複製品的權限及ID與原來的一樣

所以利用chmod,chown來使複製物的權限與uid,gid跟原來一樣

int chmod(const char *pathname, mode_t mode);

pathname:要改變權限的檔案路徑  mode:欲改變的權限

int chown(const char *pathname, uid_t owner, gid_t  group);

pathname:要改變權限的檔案路徑 owner:欲改變的uid  group:欲改變的gip

-----------------------------------------------------------------------------------------------------------------------------------

這次作業的主要重點應該就是這些

其他像是來源、目標路徑的轉換就比較瑣碎了

作業越來越難的樣子...囧












arrow
arrow
    全站熱搜

    molimomo 發表在 痞客邦 留言(0) 人氣()