系統程式作業三:實做出與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
-----------------------------------------------------------------------------------------------------------------------------------
這次作業的主要重點應該就是這些
其他像是來源、目標路徑的轉換就比較瑣碎了
作業越來越難的樣子...囧
- Mar 24 Mon 2008 20:37
[System Programming] HW3-mycp
close
全站熱搜
留言列表
發表留言