如果您想用c語言寫.....保證您一定花轟
底下是一個本人寫的取檔函數不過重點還不在取檔方面而是在"檔案權限"的問題
先看看程式吧:
/*以open()開檔後用mmap()映射到記憶體空間tmp,可依參數fill決定是否標齊為二維字串陣列;
不論開檔成功(映射檔內資料)或失敗(tmp最少有一個ISNULL)都會傳回映射區tmp的起始位址
所以叫用此函數後一定要以free()釋放記憶體空間*
int nof2new
此參數只接受YES或NOT,傳入YES可控制kee_getfstat()在檔案不存在時將fopen()的
flags參數設為FG_DW(可讀寫,該檔不存在則建立新檔);而傳入NOT檔案不存在時flags會被設
FG_R(唯讀,開啟的檔案必須存在,這樣可令open()開檔失敗而執行開檔失敗的處置)
int flag
當不知道*phfname所指檔案的模式可傳入-1,否則會以呼叫者函數指定的flag模式開啟檔案
此參數即是open()的參數flags
int mode
當不知道*phfname所指檔案的權限可傳入-1,否則會以呼叫者函數指定的mode權限開啟檔案
此參數即是open()的參數mode
以上二值任一值(flag,mode)為-1時lee_getfstat()會受*phfname所指檔案的權限影響:
例如檔案abc.c擁有者是A權限為-rw-rw-r--;當A要開啟時open()的flags會被設為可讀寫FG_D(擁有者
限為可讀寫)mode與檔案相同;映射函數mmap()的prot會被設為PROT_READ|PROT_WRITE(映射區域可被讀寫)
而B要開啟則open()的flags設為唯讀FG_R(其它使用者權限為可讀)mode與檔案相同,mmap()的prot則
為PROT_READ(映射區域可被讀取);當B欲以自定的模式或權限開啟時open()也無法開啟:errno=EACCES
int *mapsize
映射區實際宣告的長度,此值受呼叫者函數設定*mapslen初值的影響而會有不同結果
int *mapstrn
映射區資料的列數,實際上是計算有多少個'\0'或'\n'
int *mapslen
映射區每列資料的長度,此值必須先在呼叫者函數內設好初值,有下列情形:
1.開新檔時當fill傳入的不是ISNULL則*mapslen必須要設比0大的初值
2.mapslen傳入<=0時表示不要將tmp標齊成固定寬度這樣傳回的tmp就是一個不定長度的二維陣列
以'\n'間隔,其實也就是一個一維陣列從*(tmp+0)開始到*(tmp+tmpsize)
3.mapslen>0會傳回一個長寬為[mapstrn][mapslen]的二維陣列,其mapslen還要參考fill的狀況決定:
當fill傳入非ISNULL該二維陣列是以mapslen為一頁寬度,做法是將取出的最長字串長度x除以mapslen
得出頁數xpgn後令mapslen=(xpgn*mapslen)+1;
如*mapslen=10,fill!=ISNULL,x=25則該二維陣列的mapslen是30+1(xpgn=3頁 * mapslen)+1
如*mapslen=10,fill=ISNULL, x=25則該二維陣列的mapslen是25+1(x+1)
int *fotflags
開檔的模式,本函數可依該檔模式及權限將將檔案開啟(叫用lee_getfstat()設定)而這個
參數即是告訴呼叫者函數該檔將以何種模式(可讀寫FG_D,唯讀FG_R,唯寫FG_W)開啟的;當開啟的是新檔
案則設為FG_DW(可讀寫,開新檔案)
*/
char *lee_fout2mem(char *phfname,int nof2new,
int flag,int mode,int fill,
int *mapsize,int *mapstrn,int *mapslen,int *fotflags,
int *foterr)
{
int fd;
FILE *fp;
char *start;
char *tmp;
int xn,yn,xpgn,moderr,i,x,y,tmpsize;
int filesize,openflag,openmode,mapprot,mapflag;
/*依*phfname所指檔案的模式及權限設定open()的flags及mode還有mmap()的prot及flag*/
lee_getfstat(phfname,nof2new,&filesize,&openflag,&openmode,&mapprot,&mapflag);
/*
mvprintw(0,0," ");
mvprintw(0,0,"11111");
refresh();
/**/
if(flag==-1 || mode==-1)/*以stat()取得的檔案權限開啟*phfname所指檔案*/
{
fd=open(phfname,openflag,openmode);
*fotflags=openflag;
}
else/*以呼叫者函數指定的模式和權限開啟*phfname所指檔案(一般用來開啟一個不存在的新檔)*/
{
fd=open(phfname,flag,mode);
*fotflags=flag;
}
if(fd==-1)/*開檔失敗*/
{
*foterr=errno;
x=*mapslen+1;
tmp=malloc(x);
memset(tmp,fill,x);
*(tmp+x)=ISNULL;
*mapslen=x;
*mapstrn=1;
*mapsize=x;
return(&*tmp);
}
/*
mvprintw(0,0,"1111122222");
refresh();
/**/
if(filesize<1)/*檔案大小是0,但要標齊時宣告一個空列傳回*/
{
x=*mapslen+1;
tmp=malloc(x);
memset(tmp,fill,x);
*(tmp+x)=ISNULL;
*mapslen=x;
*mapstrn=1;
*mapsize=x;
*foterr=FOTOK;
close(fd);/*關閉檔案*/
return(&*tmp);
}
/*
mvprintw(0,0,"111112222233333");
refresh();
/**/
/*將檔案映射到start*/
start=mmap(NULL,filesize,mapprot,mapflag,fd,0);
if(start==MAP_FAILED)/*映射失敗*/
{
*foterr=errno;
x=*mapslen+1;
tmp=malloc(x);
memset(tmp,fill,x);
*(tmp+x)=ISNULL;
*mapslen=x;
*mapstrn=1;
*mapsize=x;
close(fd);/*關閉檔案*/
return(&*tmp);
}
/*
mvprintw(0,0,"11111222223333344444");
refresh();
/**/
y=lee_strszyele(start,filesize);/*先找出共有幾列(幾個換行號)*/
x=lee_strszxele(start,filesize);/*再找出最長的字串長度(不含'\n'字元的長度)*/
if(*mapslen>0)/*要標齊*/
{
xpgn=x/(*mapslen);
if(x%(*mapslen) > 0 || xpgn==0)
xpgn+=1;
if(fill!=ISNULL)/*fill傳入非字串結束字元表示還要補空白所以x寬度應為頁數*長度*/
x=(xpgn*(*mapslen))+1;
else/*fill傳入字串結束字元表示不補空白所以x寬度應為最長的長度+1個結束字元*/
{
if(x<=*mapslen)
x=*mapslen;
else
x+=1;
}
tmpsize=x*y;
tmp=malloc(tmpsize);
lee_strszprim(tmp,start,filesize,x-1,fill);/*標齊為x寬度*/
*mapstrn=y;
*mapslen=x;
}
else
{
/**mapslen傳入<=0表示不要標齊(不定長度的二維陣列以'\n'間隔,或是一個一維陣列)*/
tmp=malloc(filesize);
lee_strszcpy(tmp,start,filesize);
tmpsize=filesize;
*mapstrn=y;
*mapslen=x;
}
munmap(start,filesize);/*解除檔案映射*/
/*
mvprintw(0,0,"1111122222333334444455555");
refresh();
/**/
/*
mvprintw(21,0,"tmpsize=%d filesize=%d xpgn=%d 222...fopen2mem()",
tmpsize,filesize,xpgn);
for(i=0,x=1,y=22;i<=tmpsize;i++,x+=3)
{
if(x>=90)
{
x=1;
y+=1;
}
if(i>=180)
break;
mvprintw(y,x,"%d",*(tmp+i));
}
refresh();
*/
close(fd);/*關閉檔案*/
*mapsize=tmpsize;
*foterr=FOTOK;
return(&*tmp);
}
有點想放棄了嗎?那就聽pail大大的:寫成 script
如果不想放棄!!前面說過了:重點在"檔案權限"的問題
原因是因為如果您使用開檔函數如open()開啟一個檔案時有個"flag"的參數
這個flag參數就是您要將該檔以何種權限開啟的意思,如一個-rwxr-xr-x權
限的檔案以-rwxrwxrwx開啟就會失敗,所以函數一開始有一個lee_getfstat()
函數就是做這件事的,程式原碼如下:
void lee_getfstat(char *phfname,int nof2new,
int *fsize,int *fflag,int *fmode,
int *mprot,int *mflag)
{
struct stat buf;
int uuid,ugid;/*目前行程使用者的uid,gid*/
int fuid,fgid;/*字串*phfname所指檔案的uid,gid*/
int mod;
/*需將errno設為無錯誤,因為stat()在檔案不存在狀態下會將errno設為ENOENT後下次不
是ENOENT時不會將其設回來,如此一來在nof2new參數是NOT時第1次是ENOENT狀態以後叫用
本函數也都會被判為ENOENT(不論是否成功)而造成以後的存取都是ENOENT的錯誤*/
errno=0;
stat(phfname,&buf);/*取得*phfname檔案的狀態*/
if(errno==ENOENT)/*檔案不存在*/
{
*fsize=0;
if(nof2new==YES)/*要建新檔*/
*fflag=FG_DW;/*可讀寫,該檔不存在則建立新檔的旗標*/
else
*fflag=FG_R;/*唯讀,開啟的檔案必須存在,這樣可令open()開檔失敗*/
*fmode=FM_RWXRWXRX;/*使用者可讀寫執行,群組可讀寫執行,其它人可讀可執行的權限*/
*mprot=(PROT_READ | PROT_WRITE);/*映射區可讀取及寫入*/
*mflag=MAP_SHARED;/*映射區寫入的資料會覆製回檔案且允許其它映射該區的行程共享*/
return;
}
/*
mvprintw(1,0,"uuid=%d ugid=%d fuid=%d fgid=%d *",uuid,ugid,fuid,fgid);
refresh();
*/
/*uid,gid主要是可過濾出其它人開啟該檔的權限,如無這些參數將無法辨別該檔對群組及其它使用者
的存取權限,例如一檔案權限可讓其它使用者有讀的權限,當沒有這4個參數在下面的判斷式時本函數
將無法設定open()及mmap()開檔參數
例如檔案abc.c擁有者是A權限是-rw-rw-r--(擁有者A具有可讀寫權限,其它使用者只具讀取權限),如果
沒有uuid,fuid的判斷時當B要開啟abc.c時第一個判斷擁有者可讀寫即成立而將FFLAG設為FG_D(該檔的
其它使用者只具讀取權限應是以FG_R開檔才對)所以當呼叫者函數以open(phfname,FG_D,mode)開啟時就
會發生"存取動作被拒絕,權限不足 EACCES errno=13"的錯誤*/
uuid=geteuid();
ugid=getegid();
fuid=buf.st_uid;
fgid=buf.st_gid;
mod=buf.st_mode;/*暫時變數,主要讓判斷式較短*/
if(((mod & S_IRUSR) && (mod & S_IWUSR) && uuid==fuid) || /*擁有者可讀寫*/
((mod & S_IRGRP) && (mod & S_IWGRP) && ugid==fgid) || /*群組可讀寫*/
((mod & S_IROTH) && (mod & S_IWOTH)) )/*其它人可讀寫*/
{
*fflag=FG_D;/*open()以可讀寫的O_RDWR模式開啟*/
*mprot=(PROT_READ | PROT_WRITE);/*mmap()的保護模式是可被讀取及寫入的*/
}
else if(((mod & S_IRUSR) && uuid==fuid) || /*擁有者可讀*/
((mod & S_IRGRP) && ugid==fgid) || /*群組可讀*/
((mod & S_IROTH)) )/*其它人可讀*/
{
*fflag=FG_R;/*open()以唯讀的O_RDONLY模式開啟*/
*mprot=PROT_READ;/*mmap()的保護模式是可被讀取的*/
}
else if(((mod & S_IWUSR)) || /*擁有者可寫*/
((mod & S_IWGRP)) || /*群組可寫*/
((mod & S_IWOTH)) )/*其它人可寫*/
{
*fflag=FG_W;/*open()以唯寫的O_WRDONLY模式開啟*/
*mprot=PROT_WRITE;/*mmap()的保護模式是可被寫入的*/
}
else/*無開啟權限*/
{
/*嘗試以唯讀開啟*/
*fflag=FG_R;/*open()以唯讀的O_RDONLY模式開啟*/
*mprot=PROT_READ;/*mmap()的保護模式是可被讀取的*/
}
*fmode=(buf.st_mode & FM_RWXRWXRWX);/*open()以*phfname檔的權限開啟*/
*mflag=MAP_SHARED;/*映射區寫入的資料會覆製回檔案且允許其它映射該區的行程共享*/
*fsize=buf.st_size;
/*
mvprintw(2,0,"fsize=%d fflag=%d fmode=%d mprot=%d mflag=%d *",
*fsize,*fflag,*fmode,*mprot,*mflag);
refresh();
*/
}
相信看到這裡您一定認為可以了吧!....不!
還有路徑的問題,一個可備份檔案的程式怎能不考慮到子目錄的問題呢!
路徑部份的程式碼更長一點本人就不再貼了(有興趣的麻煩說一聲)
所以還是聽harrier大大及pail大大的..找簡單一點的方法吧!!
這是前陣子寫可以在文字介面看檔的一個小程式(已可看檔不過還有問題)
如果有人在以前玩過DOS的大補帖(泡麵),裡面都有一個CView的程式吧(台灣人寫的喔)
差不多就是那個樣子了,不過沒它那麼強就是了^^!