Linux C: 文件操作相关的系统调用
一、常見的文件操作相關(guān)的系統(tǒng)調(diào)用
| 普通權(quán)限的系統(tǒng)調(diào)用 | 函數(shù) | 說明 |
| int access(char *pathname,int mode) | 檢查對某個(gè)文件的權(quán)限 | |
| int chdir(const char *path) | * 變更目錄 | |
| int chmod(char *path,model_t mode) | * 更改某個(gè)文件的權(quán)限 | |
| int chown(char *name,int uid,int gid) | * 更改文件的所有人 | |
| int chroot(char *pathname); | 將(邏輯)根目錄更改為路徑名 | |
| char *getcwd(char *buf , int size) | * 獲取CWD的絕對路徑名 | |
| int mkdir(char *pathname,model_t mode) | * 創(chuàng)建目錄 | |
| int rmdir(char *pathname) | * 移除目錄 | |
| int link(char *oldpath,char *newpath); | * 將新文件名硬鏈接到舊文件名 | |
| int unlink(char *pathname) | 減少文件的鏈接數(shù);如果數(shù)值變成0則刪除文件 | |
| int symlink(char *oldpath,char *newpath) | 為文件創(chuàng)建一個(gè)符號連接 | |
| int readlink(char *path,char *buf,int bufsize) | 讀取符號鏈接文件的內(nèi)容 | |
| int rename(char *oldpath,char *newpath | * 重命名文件 | |
| int utime(char *pathname,struct utimebuf *time) | * 更改文件的訪問和修改時(shí)間 | |
| int stat(char *filename,struct stat *buf) | 獲取文件的狀態(tài)信息 | |
| int fstat(int filedes,struct stat *buf) | 獲取文件的狀態(tài)信息 | |
| int lstat(char *filename,struct stat *buf) | * 獲取文件的狀態(tài)信息 | |
| int open(char *filr,int flags,int mode) | * 打開一個(gè)文件進(jìn)行讀、寫、追加 | |
| int close(int fd) | * 關(guān)閉打開的 文件描述符 | |
| int read(int fd,char buf[],int count) | * 讀取打開的 文件描述符 | |
| int write(int fd,char buf[],int count) | * 寫入打開的 文件描述符 | |
| int lseek(int fd,int offset,int whence) | 重新定位文件描述符的讀/寫偏移量 | |
| int dup(int oldfd,int newfd) | 將文件描述符復(fù)制到最小可用描述符編號中 | |
| int dup2(int oldfd,int newfd) | 先將newfd關(guān)閉,再把oldfd賦值到newfd中 | |
| int umask(int umask); | 設(shè)置文件創(chuàng)建掩碼;文件權(quán)限為(mask &~umask) | |
| 需要超級用戶權(quán)限的系統(tǒng)調(diào)用 | int mount(char *specialfile, char *mountDir) | 將文件系統(tǒng)添加到掛載點(diǎn)目錄上 |
| int umount(char *dir); | 分離掛載的文件系統(tǒng) | |
| int mknod(char * path,int model,int device); | 創(chuàng)建特殊文件 |
二、st_mode 標(biāo)志
| 宏定義? | 值(十進(jìn)制) | 含義 |
| S_IFMT | 0170000 | 文件類型位域的位掩碼 |
| S_IFSOCK | 0140000 | socket套接字 |
| S_IFLNK | 0120000 | symbolic link 符號鏈接 |
| S_IFREG | 0100000 | 常規(guī)文件 |
| S_IFBLK | 0060000 | 塊設(shè)備 |
| S_IFDIR | 0040000 | 目錄 |
| S_IFCHR | 0020000 | 字符設(shè)備 |
| S_IFIFO | 0010000 | fifo先進(jìn)先出 |
| S_ISUID | 0004000 | 設(shè)置UID位 |
| S_ISGID | 0002000 | 設(shè)置GID位 |
| S_ISVTX | 0001000 | 設(shè)置粘滯位(Sticky bit) |
| S_IRWXU | 00700 | 當(dāng)前文件的所有者所有權(quán)限 |
| S_IRUSR | 00400 | 當(dāng)前文件的所有者讀權(quán)限 |
| S_IWUSR | 00200 | 當(dāng)前文件的所有者寫權(quán)限 |
| S_IXUSR | 00100 | 當(dāng)前文件的所有者執(zhí)行權(quán)限 |
| S_IRWXG | 00070 | 當(dāng)前文件的組所有權(quán)限 |
| S_IRGRP | 00040 | 當(dāng)前文件的組讀權(quán)限 |
| S_IWGRP | 00020 | 當(dāng)前文件的組寫權(quán)限 |
| S_IXGRP | 00010 | 當(dāng)前文件的組執(zhí)行權(quán)限 |
| S_IRWXO | 00007 | 當(dāng)前文件的其他用戶所有權(quán)限 |
| S_IROTH | 00004 | 當(dāng)前文件的其他用戶讀權(quán)限 |
| S_IWOTH | 00002 | 當(dāng)前文件的其他用戶寫權(quán)限 |
| S_IXOTH | 00001 | 當(dāng)前文件的其他用戶執(zhí)行權(quán)限 |
三、文件狀態(tài)結(jié)構(gòu)體? stat
struct stat {dev_t st_dev; //文件的設(shè)備編號ino_t st_ino; //節(jié)點(diǎn)mode_t st_mode; //文件的類型和存取的權(quán)限nlink_t st_nlink; //連到該文件的硬連接數(shù)目,剛建立的文件值為1uid_t st_uid; //用戶IDgid_t st_gid; //組IDdev_t st_rdev; //(設(shè)備類型)若此文件為設(shè)備文件,則為其設(shè)備編號off_t st_size; //文件字節(jié)數(shù)(文件大小)unsigned long st_blksize; //塊大小(文件系統(tǒng)的I/O 緩沖區(qū)大小)unsigned long st_blocks; //塊數(shù)time_t st_atime; //最后一次訪問時(shí)間time_t st_mtime; //最后一次修改時(shí)間time_t st_ctime; //最后一次改變時(shí)間(指屬性) };讀取文件時(shí),可以獲取文件的文件屬性, 可以用以下三種方法
int? stat(const char *file_name ,struct stat *buf)? ? 按文件名獲得文件的stat信息,如果時(shí)鏈接文件獲取鏈接文件所指向的文件信息
int? fstat(int filedes? ,struct stat *buf)? ? ? ?和stat函數(shù)效果一樣,只不過傳入的參數(shù)時(shí)文件描述符
int? lstat(const char *file_name ,struct stat *buf)? ? 按文件名獲得文件的stat信息,如果時(shí)鏈接文件獲取文件本身的信息??
下面展示linux 命令? ls 原理的程序:(不支持通配符)
open () 方法是打開文件,遵循符號鏈接,但是如果想打開文件內(nèi)容本身,應(yīng)調(diào)用
int readlink(char * pathname ,char buf[] , int bufsize);
/*************myls.c********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <time.h> #include <sys/types.h> #include <dirent.h> #include <unistd.h> struct stat mystat,*sp; char *t1 = "xwrxwrxwr-------"; char *t2 = "----------------";int ls_file(char *fname){struct stat fstat ,*sp;int r,i;char ftime[64];sp =& fstat;if( (r = lstat(fname,&fstat)) <0 ){printf("can't stat %s\n",fname);exit(1);}if ( (sp->st_mode &0xF000) == 0x8000 ){// S_ISREGprintf("%c",'-');}else if ( (sp->st_mode &0xF000) == 0x4000 ){// S_ISDIRprintf("%c",'d');}else if ( (sp->st_mode &0xF000) == 0xA000 ){// S_ISLNKprintf("%c",'l');}for ( i =8 ; i>=0 ;i--){ if (sp->st_mode & (1 << i )){printf("%c",t1[i]);} else {printf("%c",t2[i]);}}printf("%4d ",sp->st_nlink);printf("%4d ",sp->st_gid);printf("%4d ",sp->st_uid);printf("%8d ",sp->st_size);//print time strcpy(ftime ,ctime(&sp->st_ctime));ftime[strlen(ftime) -1 ] =0;printf ("%s " , ftime);//print name printf ("%s",basename(fname));//if symbolic file , print symfile ->linknameif( (sp->st_mode &0xF000) ==0xA000){//uss readlink() to read linknamechar *linkname;readlink (fname , linkname,1024);printf(" -> %s" , linkname); //print linked name}printf("\n"); }int ls_dir(char *dname){ struct dirent *ep ;DIR *dp = opendir(dname);if(!dp){printf("no such dir %s\n",dname);exit(1);}char newpath[1024];while( ep = readdir(dp)){strcpy(newpath,dname);strcat(newpath , ep ->d_name);ls_file(newpath);} }int main(int argc , char *argv[]){struct stat mystat, *sp =&mystat;int r ;char *filename , path[1024] ,cwd[256];filename = "./";if (argc >1){filename =argv[1];}if( r = lstat(filename,sp) < 0 ){printf("no such file %s\n",filename);}strcpy(path , filename);if(path[0] != '/'){//相對路徑getcwd(cwd,256);strcpy(path,cwd); strcat(path ,"/");strcat(path , filename);}if(S_ISDIR(sp -> st_mode)){printf ("path : %s\n", path);ls_dir(path);}elsels_file(path); }四、復(fù)制文件, cp -r? [srcPath]? ?[destPath]原理
案例分析:
1)src必須存在,dest如果不存在則需要?jiǎng)?chuàng)建
2)如果src 是一個(gè)文件,dest 是一個(gè)文件或目錄。如果是目錄則創(chuàng)建同名文件,如果是文件,則直接復(fù)制文件內(nèi)容
3)如果src是一個(gè)目錄,那么dest必須一定是一個(gè)目錄,通過readdir遍歷src目錄下的文件和字目錄,復(fù)制到dest中
4)如果src 和dest 是同名文件則不復(fù)制 , 如果dest 是src的后代目錄則不能復(fù)制,包括自身。
可以分3個(gè)層級來組織程序:
1)最底層:文件復(fù)制文件 cpf2f? ?
2)中間層: 將文件復(fù)制到目錄中? cpf2d ,判斷dest目錄存在,然后調(diào)用 1 步驟
3)? 最高層:? 目錄復(fù)制到目錄cp2d2, 通過readdur遍歷src目錄,如果成員是文件則調(diào)用步驟2),如果成員是目錄則?遞歸調(diào)用步驟 3)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <libgen.h>#include <fcntl.h>// for stat syscalls #include <sys/stat.h> #include <unistd.h>// for opendir, readdir syscalls #include <sys/types.h> #include <dirent.h>// cp file to fileint cpf2f(char *src, char *dst) {int fd, gd, n, r1, r2, mode;char buf[1024];struct stat st1, st2;r1 = lstat(src, &st1);if (r1 < 0){printf("src %s does not exist\n", src);return -1;}if (S_ISDIR(st1.st_mode)){printf("src %s is not a file\n", src);return -1;}r2 = lstat(dst, &st2);if (r2 == 0){ // dst existif (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino){printf("Src %s and dst %s are the same file\n", src, dst);return -1;}}if (r2 < 0){ // dst not exist; src if a filemode = st1.st_mode;if (S_ISLNK(mode)){printf("%s is a symlink file ==> ", src);n = readlink(src, buf, 1024); buf[n] = 0;printf("%s\n", buf);// make a symbolic filesymlink(buf, dst);return 0;}}// dst not but src is NOT LNK OR dst exist: cp src to dstfd = open(src, O_RDONLY); gd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode);while( (n=read(fd, buf, 1024)) )write(gd, buf, n);close(fd); close(gd);return 0;}int cpf2d(char *f1, char *f2) {int n, r1, r2, size;char buf[1024], name[128], f3[128], temp[128];DIR *gd;struct stat st, st3;struct dirent *ep;printf("cpf2d: cp %s into %s\n", f1, f2);r2 = lstat(f2, &st);if (r2 < 0 || S_ISDIR(st.st_mode)==0){printf("no such dir %s\n", f2);return -1;}strcpy(f3, f2); strcat(f3, "/");strcat(f3, basename(f1));if (lstat(f3, &st) < 0){ // f2/basename(f1) does not existreturn cpf2f(f1, f3);}// f2/basename(f1) exists in f2/if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))return cpf2f(f1, f3);else{printf("cpf2d but f1 is a DIR, can't be true\n");return cpf2d(f1, f3);} }int sameFile(char *f1, char *f2) {struct stat st1, st2;stat(f1, &st1); stat(f2, &st2);if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)return 1;return 0; }int checkdir(char *f1, char *f2) {while(!sameFile(f1, "/")){if (sameFile(f1, f2))return 1;strcat(f2, "/..");}return 0; }//int checkDir(char *f1, char *f2) //{ // char temp[128], t[128]; // int r0, r1, r2; // struct stat st0, st1, st2; // //printf("checkdir: %s %s\n", f1, f2); // // r0 = stat("/", &st0); printf("r0=%d root DIR = (%x %ld)\n", r0, (int)st0.st_dev, (long)st0.st_ino); // // r1 = stat(f1, &st1); // // //printf("r1=%d st1=[%x %ld]\n", r1, (int)st1.st_dev, (long)st1.st_ino); // // strcpy(temp, f2); strcat(temp, "/.."); // while (1){ // //printf("%s ", temp); // // r2 = stat(temp, &st2); // //printf("r2=%d st2=[%x %ld]\n", r2, (int)st2.st_dev, (long)st2.st_ino); // // if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino){ // //printf("found a match\n"); // return 1; // } // // if (st2.st_dev == st0.st_dev && st2.st_ino == st0.st_ino){ // //printf("reached /\n"); // break; // } // strcat(temp, "/.."); // } // return 0; //}int cpdir(char *f1, char *f2){int n, r1, r2, found;char buf[1024], name[128], dname[128], temp[128];char src[128], dst[128], f3[128];DIR *fd, *gd;struct dirent *ep;struct stat st1, st2, st3;fd = opendir(f1);while( (ep = readdir(fd)) ){if (strcmp(ep->d_name, ".")==0 || strcmp(ep->d_name, "..")==0)continue;strcpy(src, f1); strcat(src, "/"); strcat(src, ep->d_name);strcpy(dst, f2); strcat(dst, "/"); strcat(dst, ep->d_name);r1 = lstat(src, &st1);if (S_ISREG(st1.st_mode) || S_ISLNK(st1.st_mode)){printf("cpf2f: %s to %s\n", src, dst);cpf2d(src, f2);}if (S_ISDIR(st1.st_mode)){/******r = stat(dst, &st3);if (r<0)mkdir(dst, 0755);*******///printf("recursive cp dir %s to %s\n", src, dst); cpd2d(src, dst);}}closedir(fd);return 1; }// recursively cp dir into dir int cpd2d(char *f1, char *f2) {int n, r1, r2, found;char buf[1024], name[128], dname[128], temp[128];char temp1[128], temp2[128];char src[128], dst[128], f3[128];DIR *fd, *gd;struct dirent *ep;struct stat st1, st2, st3;//printf("entering cpd2d : %s %s\n", f1, f2);printf("cpd2d: %s %s\n", f1, f2);// 1. if f1 not exist => error outr1 = lstat(f1, &st1);if (r1 < 0 || S_ISDIR(st1.st_mode)==0){printf("%s is not a dir\n", f1);return -1;}// check f2:r2 = lstat(f2, &st2);// 2. if f2 not exist => mkdir f2if (r2 < 0){ // f2 not existprintf("mkdir: %s\n", f2);r2 = mkdir(f2, 0755);if (r2<0){printf("DIR %s already exists\n", f2);}return cpdir(f1, f2);}// f2 exist case:r2 = stat(f2, &st2);// 3. f2 existed but NOT DIR ==> error outif (r2 >= 0 && S_ISDIR(st2.st_mode)==0){printf("%s is not a dir\n", f2);return -1;}// 4. if f1 and f2 are SAME ==> error outif (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino){printf("can't cp DIR f1 to itself\n");return -1;}// 5. check f2 is NOT under f1: if so error out// from f2, stat f2/.., f2/../../ until /; check whether ANY of these is f1if (checkdir(f1, f2)){printf("%s is inside %s\n", f2, f1);return -1;}// f2 existed:if (r2 >=0 ){ // f2 exist and is DIR: check whether same as f1 basenamestrcpy(temp1, f1);strcpy(temp2, f2);if (strcmp(basename(temp1), basename(temp2))){ // NOT same namestrcpy(temp, f2); strcat(temp, "/");strcpy(temp1, f1);strcat(temp, basename(temp1)); // create DIR f2/basenem(f1)printf("mkdir: %s\n", temp);r2 = mkdir(temp, 0755);}printf("mkdir2 DIR %s already exists\n", temp);return cpdir(f1, temp);}// f2 exist but NOT same as basename of f1return cpdir(f1, f2); }int myrcp(char *f1, char *f2) {struct stat st1, st2; int r1, r2, m1, m2, c;// MUST use lstat() because f1 may be a symlink filer1 = lstat(f1, &st1);if (r1 < 0){printf("no src file %s\n", f1);return -1;}m1 = st1.st_mode;if (!S_ISREG(m1) && !S_ISDIR(m1) && !S_ISLNK(m1)){printf("src is not REG, DIR or LNK file\n");exit(2);}r2 = lstat(f2, &st2);m2 = st2.st_mode;if (r2 < 0){ // f2 does NOT existif (S_ISREG(st1.st_mode) || S_ISLNK(st1.st_mode))return cpf2f(f1, f2);if (S_ISDIR(st1.st_mode))return cpd2d(f1, f2);}if (r2==0){ // f2 existsif (!S_ISREG(m1) && !S_ISDIR(m1) && !S_ISLNK(m1)){printf("dst %s is not REG, DIR or LNK file\n", f2);exit(2);}}if (r2 == 0){ // f2 exists; check whether f1 == f2if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino){printf("%s and %s are the same file\n", f1, f2);return -1;}}if (S_ISREG(m1) || S_ISLNK(m1)){if (S_ISREG(m2))return cpf2f(f1, f2);if (S_ISDIR(m2))return cpf2d(f1,f2);}printf("%s is not a file; try dir\n", f1);if (S_ISDIR(m1)){if (S_ISREG(m2)){printf("can't cp dir into file\n");return -1;}r2 = stat(f2, &st2);if (r2 < 0) // f2 does not exist yetmkdir(f2, 0755);r2 = stat(f2, &st2);m2 = st2.st_mode;if (S_ISDIR(m2)){printf("cp dir to dir\n");return cpd2d(f1, f2);}} }int main(int argc, char *argv[]) {if (argc < 3){printf("Usage: rcp SRC DST\n");exit(1);}return myrcp(argv[1], argv[2]); }?
總結(jié)
以上是生活随笔為你收集整理的Linux C: 文件操作相关的系统调用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 转:ext2文件系统详解
- 下一篇: Linux C: IO库函数,文件流缓冲