X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=cpmfs.c;h=1d4524ed87aed0b5177c65e788cbbd475622df47;hb=a2d7d89e8d4dbd8860a2f1fd624fcdb46eda35fc;hp=cabe8ee9f885ba07477e28ef0d321fc338dc5949;hpb=32087c67d53a8f8058b359388f23e2dbc9436d54;p=debian%2Fcpmtools diff --git a/cpmfs.c b/cpmfs.c index cabe8ee..1d4524e 100644 --- a/cpmfs.c +++ b/cpmfs.c @@ -1,12 +1,5 @@ /* #includes */ /*{{{C}}}*//*{{{*/ -#undef _POSIX_SOURCE -#define _POSIX_SOURCE 1 -#undef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 2 - -#ifdef DMALLOC -#include "dmalloc.h" -#endif +#include "config.h" #include #include @@ -16,9 +9,13 @@ #include #include #include -#include "config.h" + #include "cpmdir.h" #include "cpmfs.h" + +#ifdef USE_DMALLOC +#include +#endif /*}}}*/ /* #defines */ /*{{{*/ #undef CPMFS_DEBUG @@ -122,6 +119,81 @@ static int isMatching(int user1, const char *name1, const char *ext1, int user2, } /*}}}*/ +/* time conversions */ +/* cpm2unix_time -- convert CP/M time to UTC */ /*{{{*/ +static time_t cpm2unix_time(int days, int hour, int min) +{ + /* CP/M stores timestamps in local time. We don't know which */ + /* timezone was used and if DST was in effect. Assuming it was */ + /* the current offset from UTC is most sensible, but not perfect. */ + + int year,days_per_year; + static int days_per_month[]={31,0,31,30,31,30,31,31,30,31,30,31}; + char **old_environ; + static char gmt0[]="TZ=GMT0"; + static char *gmt_env[]={ gmt0, (char*)0 }; + struct tm tms; + time_t lt,t; + + time(<); + t=lt; + tms=*localtime(<); + old_environ=environ; + environ=gmt_env; + lt=mktime(&tms); + lt-=t; + tms.tm_sec=0; + tms.tm_min=((min>>4)&0xf)*10+(min&0xf); + tms.tm_hour=((hour>>4)&0xf)*10+(hour&0xf); + tms.tm_mday=1; + tms.tm_mon=0; + tms.tm_year=78; + tms.tm_isdst=-1; + for (;;) + { + year=tms.tm_year+1900; + days_per_year=((year%4)==0 && ((year%100) || (year%400)==0)) ? 366 : 365; + if (days>days_per_year) + { + days-=days_per_year; + ++tms.tm_year; + } + else break; + } + for (;;) + { + days_per_month[1]=(days_per_year==366) ? 29 : 28; + if (days>days_per_month[tms.tm_mon]) + { + days-=days_per_month[tms.tm_mon]; + ++tms.tm_mon; + } + else break; + } + t=mktime(&tms)+(days-1)*24*3600; + environ=old_environ; + t-=lt; + return t; +} +/*}}}*/ +/* unix2cpm_time -- convert UTC to CP/M time */ /*{{{*/ +static void unix2cpm_time(time_t now, int *days, int *hour, int *min) +{ + struct tm *tms; + int i; + + tms=localtime(&now); + *min=((tms->tm_min/10)<<4)|(tms->tm_min%10); + *hour=((tms->tm_hour/10)<<4)|(tms->tm_hour%10); + for (i=1978,*days=0; i<1900+tms->tm_year; ++i) + { + *days+=365; + if (i%4==0 && (i%100!=0 || i%400==0)) ++*days; + } + *days += tms->tm_yday+1; +} +/*}}}*/ + /* allocation vector bitmap functions */ /* alvInit -- init allocation vector */ /*{{{*/ static void alvInit(const struct cpmSuperBlock *d) @@ -146,7 +218,7 @@ static void alvInit(const struct cpmSuperBlock *d) { block=(unsigned char)d->dir[i].pointers[j]; if (d->size>=256) block+=(((unsigned char)d->dir[i].pointers[++j])<<8); - if (block) + if (block && blocksize) { #ifdef CPMFS_DEBUG fprintf(stderr,"alvInit: allocate block %d\n",block); @@ -252,36 +324,6 @@ static int writeBlock(const struct cpmSuperBlock *d, int blockno, const char *bu /*}}}*/ /* directory management */ -/* readPhysDirectory -- read directory from drive */ /*{{{*/ -static int readPhysDirectory(const struct cpmSuperBlock *drive) -{ - int i,blocks,entry; - - blocks=(drive->maxdir*32+drive->blksiz-1)/drive->blksiz; - entry=0; - for (i=0; idir+entry),0,-1)==-1) return -1; - entry+=(drive->blksiz/32); - } - return 0; -} -/*}}}*/ -/* writePhysDirectory -- write directory to drive */ /*{{{*/ -static int writePhysDirectory(const struct cpmSuperBlock *drive) -{ - int i,blocks,entry; - - blocks=(drive->maxdir*32+drive->blksiz-1)/drive->blksiz; - entry=0; - for (i=0; idir+entry),0,-1)==-1) return -1; - entry+=(drive->blksiz/32); - } - return 0; -} -/*}}}*/ /* findFileExtent -- find first/next extent for a file */ /*{{{*/ static int findFileExtent(const struct cpmSuperBlock *sb, int user, const char *name, const char *ext, int start, int extno) { @@ -313,7 +355,6 @@ static int findFreeExtent(const struct cpmSuperBlock *drive) static void updateTimeStamps(const struct cpmInode *ino, int extent) { struct PhysDirectoryEntry *date; - struct tm *t; int i; int ca_min,ca_hour,ca_days,u_min,u_hour,u_days; @@ -321,30 +362,11 @@ static void updateTimeStamps(const struct cpmInode *ino, int extent) #ifdef CPMFS_DEBUG fprintf(stderr,"CPMFS: updating time stamps for inode %d (%d)\n",extent,extent&3); #endif - /* compute ctime/atime */ /*{{{*/ - t=localtime(ino->sb->cnotatime ? &ino->ctime : &ino->atime); - ca_min=((t->tm_min/10)<<4)|(t->tm_min%10); - ca_hour=((t->tm_hour/10)<<4)|(t->tm_hour%10); - for (i=1978,ca_days=0; i < 1900 + t->tm_year; ++i) - { - ca_days+=365; - if (i%4==0 && (i%100!=0 || i%400==0)) ++ca_days; - } - ca_days += t->tm_yday + 1; - /*}}}*/ - /* compute mtime */ /*{{{*/ - t=localtime(&ino->mtime); - u_min=((t->tm_min/10)<<4)|(t->tm_min%10); - u_hour=((t->tm_hour/10)<<4)|(t->tm_hour%10); - for (i=1978,u_days=0; i < 1900 + t->tm_year; ++i) - { - u_days+=365; - if (i%4==0 && (i%100!=0 || i%400==0)) ++u_days; - } - u_days += t->tm_yday + 1; - /*}}}*/ + unix2cpm_time(ino->sb->cnotatime ? ino->ctime : ino->atime,&ca_days,&ca_hour,&ca_min); + unix2cpm_time(ino->mtime,&u_days,&u_hour,&u_min); if ((ino->sb->type==CPMFS_P2DOS || ino->sb->type==CPMFS_DR3) && (date=ino->sb->dir+(extent|3))->status==0x21) { + ino->sb->dirtyDirectory=1; switch (extent&3) { case 0: /* first entry */ /*{{{*/ @@ -422,6 +444,34 @@ static int diskdefReadSuper(struct cpmSuperBlock *d, const char *format) else if (strcmp(argv[0],"blocksize")==0) d->blksiz=strtol(argv[1],(char**)0,0); else if (strcmp(argv[0],"maxdir")==0) d->maxdir=strtol(argv[1],(char**)0,0); else if (strcmp(argv[0],"skew")==0) d->skew=strtol(argv[1],(char**)0,0); + else if (strcmp(argv[0],"skewtab")==0) + { + int pass,sectors; + + for (pass=0; pass<2; ++pass) + { + char *s; + + sectors=0; + for (s=argv[1]; *s; ) + { + int phys; + char *end; + + phys=strtol(s,&end,10); + if (pass==1) d->skewtab[sectors]=phys; + if (end==s) + { + fprintf(stderr,"%s: invalid skewtab `%s' at `%s'\n",cmd,argv[1],s); + exit(1); + } + s=end; + ++sectors; + if (*s==',') ++s; + } + if (pass==0) d->skewtab=malloc(sizeof(int)*sectors); + } + } else if (strcmp(argv[0],"boottrk")==0) d->boottrk=strtol(argv[1],(char**)0,0); else if (strcmp(argv[0],"logicalextents")==0) d->extents=strtol(argv[1],(char**)0,0); else if (strcmp(argv[0],"os")==0) @@ -431,6 +481,11 @@ static int diskdefReadSuper(struct cpmSuperBlock *d, const char *format) else if (strcmp(argv[1],"p2dos")==0) d->type=CPMFS_P2DOS; } } + else if (argc>0 && argv[0][0]!='#') + { + fprintf(stderr,"%s: invalid keyword `%s'\n",cmd,argv[0]); + exit(1); + } } else if (argc==2 && strcmp(argv[0],"diskdef")==0) { @@ -438,6 +493,7 @@ static int diskdefReadSuper(struct cpmSuperBlock *d, const char *format) d->skew=1; d->extents=0; d->type=CPMFS_DR3; + d->skewtab=(int*)0; if (strcmp(argv[1],format)==0) found=1; } } @@ -495,6 +551,7 @@ static int amsReadSuper(struct cpmSuperBlock *d, const char *format) d->blksiz = 128 << boot_spec[6]; d->maxdir = (d->blksiz / 32) * boot_spec[7]; d->skew = 1; /* Amstrads skew at the controller level */ + d->skewtab = (int*)0; d->boottrk = boot_spec[5]; d->size = (d->secLength*d->sectrk*(d->tracks-d->boottrk))/d->blksiz; d->extents = ((d->size>=256 ? 8 : 16)*d->blksiz)/16384; @@ -510,23 +567,23 @@ static int recmatch(const char *a, const char *pattern) while (*pattern) { - switch (*pattern) - { - case '*': - { - if (*a=='.' && first) return 1; - ++pattern; - while (*a) if (recmatch(a,pattern)) return 1; else ++a; - break; - } - case '?': + switch (*pattern) { - if (*a) { ++a; ++pattern; } else return 0; - break; + case '*': + { + if (*a=='.' && first) return 1; + ++pattern; + while (*a) if (recmatch(a,pattern)) return 1; else ++a; + break; + } + case '?': + { + if (*a) { ++a; ++pattern; } else return 0; + break; + } + default: if (tolower(*a)==tolower(*pattern)) { ++a; ++pattern; } else return 0; } - default: if (*a==*pattern) { ++a; ++pattern; } else return 0; - } - first=0; + first=0; } return (*pattern=='\0' && *a=='\0'); } @@ -558,21 +615,45 @@ void cpmglob(int optin, int argc, char * const argv[], struct cpmInode *root, in *gargc=0; cpmOpendir(root,&dir); entries=0; - dirent=realloc(dirent,sizeof(struct cpmDirent)*(dirsize=32)); - while (cpmReaddir(&dir,dirent+entries)) + dirsize=8; + dirent=malloc(sizeof(struct cpmDirent)*dirsize); + while (cpmReaddir(&dir,&dirent[entries])) { ++entries; if (entries==dirsize) dirent=realloc(dirent,sizeof(struct cpmDirent)*(dirsize*=2)); } for (i=optin; idev,d->secLength,d->sectrk,d->tracks); - /* generate skew table */ /*{{{*/ - if (( d->skewtab = malloc(d->sectrk*sizeof(int))) == (int*)0) - { - fprintf(stderr,"%s: can not allocate memory for skew sector table\n",cmd); - exit(1); - } - if (strcmp(format,"apple-do")==0) - { - static int skew[]={0,6,12,3,9,15,14,5,11,2,8,7,13,4,10,1}; - memcpy(d->skewtab,skew,d->sectrk*sizeof(int)); - } - else if (strcmp(format,"apple-po")==0) - { - static int skew[]={0,9,3,12,6,15,1,10,4,13,7,8,2,11,5,14}; - memcpy(d->skewtab,skew,d->sectrk*sizeof(int)); - } - else + if (d->skewtab==(int*)0) /* generate skew table */ /*{{{*/ { int i,j,k; + if (( d->skewtab = malloc(d->sectrk*sizeof(int))) == (int*)0) + { + fprintf(stderr,"%s: can not allocate memory for skew sector table\n",cmd); + exit(1); + } + memset(d->skewtab,0,d->sectrk*sizeof(int)); for (i=j=0; isectrk; ++i,j=(j+d->skew)%d->sectrk) { while (1) @@ -635,8 +706,24 @@ int cpmReadSuper(struct cpmSuperBlock *d, struct cpmInode *root, const char *for return -1; } /*}}}*/ - if (d->dev.opened==0) memset(d->dir,0xe5,d->maxdir*32); - else if (readPhysDirectory(d)==-1) return -1; + if (d->dev.opened==0) /* create empty directory in core */ /*{{{*/ + { + memset(d->dir,0xe5,d->maxdir*32); + } + /*}}}*/ + else /* read directory in core */ /*{{{*/ + { + int i,blocks,entry; + + blocks=(d->maxdir*32+d->blksiz-1)/d->blksiz; + entry=0; + for (i=0; idir+entry),0,-1)==-1) return -1; + entry+=(d->blksiz/32); + } + } + /*}}}*/ alvInit(d); if (d->type==CPMFS_DR3) /* read additional superblock information */ /*{{{*/ { @@ -733,9 +820,6 @@ int cpmNamei(const struct cpmInode *dir, const char *filename, struct cpmInode * int user; char name[8],extension[3]; struct PhysDirectoryEntry *date; - char **old_environ; - static char gmt0[]="TZ=GMT0"; - static char *gmt_env[]={ gmt0, (char*)0 }; int highestExtno,highestExt=-1,lowestExtno,lowestExt=-1; int protectMode=0; /*}}}*/ @@ -823,19 +907,16 @@ int cpmNamei(const struct cpmInode *dir, const char *filename, struct cpmInode * i->ino=lowestExt; i->mode=s_ifreg; i->sb=dir->sb; - old_environ=environ; - environ=gmt_env; /* for mktime() */ + /* set timestamps */ /*{{{*/ if ( (dir->sb->type==CPMFS_P2DOS || dir->sb->type==CPMFS_DR3) && (date=dir->sb->dir+(lowestExt|3))->status==0x21 ) - /* set time stamps */ /*{{{*/ { /* variables */ /*{{{*/ int u_days=0,u_hour=0,u_min=0; int ca_days=0,ca_hour=0,ca_min=0; - struct tm tms; /*}}}*/ switch (lowestExt&3) @@ -848,7 +929,7 @@ int cpmNamei(const struct cpmInode *dir, const char *filename, struct cpmInode * u_days=((unsigned char)date->name[4])+(((unsigned char)date->name[5])<<8); u_hour=(unsigned char)date->name[6]; u_min=(unsigned char)date->name[7]; - protectMode=(unsigned char)date->name[8]; + protectMode=(unsigned char)date->ext[0]; break; } /*}}}*/ @@ -877,32 +958,20 @@ int cpmNamei(const struct cpmInode *dir, const char *filename, struct cpmInode * } /*}}}*/ } - /* compute CP/M to UNIX time format */ /*{{{*/ - tms.tm_sec=0; - tms.tm_min=((ca_min>>4)&0xf)*10+(ca_min&0xf); - tms.tm_hour=((ca_hour>>4)&0xf)*10+(ca_hour&0xf); - tms.tm_mday=1; - tms.tm_mon=0; - tms.tm_year=78; - tms.tm_isdst=-1; if (i->sb->cnotatime) { - i->ctime=mktime(&tms)+(ca_days-1)*24*3600; + i->ctime=cpm2unix_time(ca_days,ca_hour,ca_min); i->atime=0; } else { i->ctime=0; - i->atime=mktime(&tms)+(ca_days-1)*24*3600; + i->atime=cpm2unix_time(ca_days,ca_hour,ca_min); } - tms.tm_min=((u_min>>4)&0xf)*10+(u_min&0xf); - tms.tm_hour=((u_hour>>4)&0xf)*10+(u_hour&0xf); - i->mtime=mktime(&tms)+(u_days-1)*24*3600; - /*}}}*/ + i->mtime=cpm2unix_time(u_days,u_hour,u_min); } - /*}}}*/ else i->atime=i->mtime=i->ctime=0; - environ=old_environ; + /*}}}*/ /* Determine the inode attributes */ i->attr = 0; @@ -982,12 +1051,12 @@ int cpmUnlink(const struct cpmInode *dir, const char *fname) drive=dir->sb; if (splitFilename(fname,dir->sb->type,name,extension,&user)==-1) return -1; if ((extent=findFileExtent(drive,user,name,extension,0,-1))==-1) return -1; + drive->dirtyDirectory=1; drive->dir[extent].status=(char)0xe5; do { drive->dir[extent].status=(char)0xe5; } while ((extent=findFileExtent(drive,user,name,extension,extent+1,-1))>=0); - if (writePhysDirectory(drive)==-1) return -1; alvInit(drive); return 0; } @@ -1018,11 +1087,11 @@ int cpmRename(const struct cpmInode *dir, const char *old, const char *new) } do { + drive->dirtyDirectory=1; drive->dir[extent].status=newuser; memcpy7(drive->dir[extent].name, newname, 8); memcpy7(drive->dir[extent].ext, newext, 3); } while ((extent=findFileExtent(drive,olduser,oldname,oldext,extent+1,-1))!=-1); - if (writePhysDirectory(drive)==-1) return -1; return 0; } /*}}}*/ @@ -1045,7 +1114,7 @@ int cpmReaddir(struct cpmFile *dir, struct cpmDirent *ent) { /* variables */ /*{{{*/ struct PhysDirectoryEntry *cur=(struct PhysDirectoryEntry*)0; - char buf[13]; + char buf[2+8+1+3+1]; /* 00foobarxy.zzy\0 */ int i; char *bufp; int hasext; @@ -1131,7 +1200,8 @@ int cpmReaddir(struct cpmFile *dir, struct cpmDirent *ent) } *bufp='\0'; /*}}}*/ - ent->reclen=strlen(buf); + assert(bufp<=buf+sizeof(buf)); + ent->reclen=bufp-buf; strcpy(ent->name,buf); ent->off=dir->pos; ++dir->pos; @@ -1262,46 +1332,19 @@ int cpmRead(struct cpmFile *file, char *buf, int count) /* cpmWrite -- write */ /*{{{*/ int cpmWrite(struct cpmFile *file, const char *buf, int count) { - int findext=1,findblock=1,extent=-1,extentno=-1,got=0,nextblockpos=-1,nextextpos=-1; + int findext=1,findblock=-1,extent=-1,extentno=-1,got=0,nextblockpos=-1,nextextpos=-1; int blocksize=file->ino->sb->blksiz; int extcap=(file->ino->sb->size<256 ? 16 : 8)*blocksize; - int block=-1,start=-1,end=-1,ptr=-1; + int block=-1,start=-1,end=-1,ptr=-1,last=-1; char buffer[16384]; while (count>0) { - if (findext) + if (findext) /*{{{*/ { extentno=file->pos/16384; extent=findFileExtent(file->ino->sb,file->ino->sb->dir[file->ino->ino].status,file->ino->sb->dir[file->ino->ino].name,file->ino->sb->dir[file->ino->ino].ext,0,extentno); nextextpos=(file->pos/extcap)*extcap+extcap; - findext=0; - findblock=1; - updateTimeStamps(file->ino,extent); - } - if (findblock) - { - if (start!=-1) - { - int last; - - last=writeBlock(file->ino->sb,block,buffer,start,end); - if (file->ino->sb->size<256) for (last=15; last>=ptr; --last) - { - if (file->ino->sb->dir[extent].pointers[last]) break; - } - else for (last=14; last>=ptr; last-=2) - { - if (file->ino->sb->dir[extent].pointers[last] || file->ino->sb->dir[extent].pointers[last+1]) break; - } - if (last==ptr) /* we wrote the last used block of this extent */ - { - file->ino->sb->dir[extent].extnol=EXTENTL((file->pos-1)/16384); - file->ino->sb->dir[extent].extnoh=EXTENTH((file->pos-1)/16384); - file->ino->sb->dir[extent].blkcnt=((file->pos-1)%16384)/128+1; - file->ino->sb->dir[extent].lrc=file->pos%128; - } - } if (extent==-1) { if ((extent=findFreeExtent(file->ino->sb))==-1) return (got==0 ? -1 : got); @@ -1311,12 +1354,19 @@ int cpmWrite(struct cpmFile *file, const char *buf, int count) file->ino->sb->dir[extent].extnoh=EXTENTH(extentno); file->ino->sb->dir[extent].blkcnt=0; file->ino->sb->dir[extent].lrc=0; + updateTimeStamps(file->ino,extent); } + findext=0; + findblock=1; + } + /*}}}*/ + if (findblock) /*{{{*/ + { ptr=(file->pos%extcap)/blocksize; if (file->ino->sb->size>=256) ptr*=2; block=(unsigned char)file->ino->sb->dir[extent].pointers[ptr]; if (file->ino->sb->size>=256) block+=((unsigned char)file->ino->sb->dir[extent].pointers[ptr+1])<<8; - if (block==0) + if (block==0) /* allocate new block, set start/end to cover it */ /*{{{*/ { if ((block=allocBlock(file->ino->sb))==-1) return (got==0 ? -1 : got); file->ino->sb->dir[extent].pointers[ptr]=block&0xff; @@ -1325,44 +1375,54 @@ int cpmWrite(struct cpmFile *file, const char *buf, int count) end=(blocksize-1)/file->ino->sb->secLength; memset(buffer,0,blocksize); } - else + /*}}}*/ + else /* read existing block and set start/end to cover modified parts */ /*{{{*/ { start=(file->pos%blocksize)/file->ino->sb->secLength; end=((file->pos%blocksize+count)>blocksize ? blocksize-1 : (file->pos%blocksize+count-1))/file->ino->sb->secLength; if (file->pos%file->ino->sb->secLength) readBlock(file->ino->sb,block,buffer,start,start); if (end!=start && (file->pos+count-1)ino->sb,block,buffer+end*file->ino->sb->secLength,end,end); } + /*}}}*/ nextblockpos=(file->pos/blocksize)*blocksize+blocksize; findblock=0; } - buffer[file->pos%blocksize]=*buf++; - ++file->pos; - if (file->ino->sizepos) file->ino->size=file->pos; - ++got; - if (file->pos==nextblockpos) { if (file->pos==nextextpos) findext=1; else findblock=1; } - --count; - } - if (start!=-1) - { - int last; - - last=writeBlock(file->ino->sb,block,buffer,start,end); - if (file->ino->sb->size<256) for (last=15; last>=ptr; --last) + /*}}}*/ + /* fill block and write it */ /*{{{*/ + file->ino->sb->dirtyDirectory=1; + while (file->pos!=nextblockpos && count) { - if (file->ino->sb->dir[extent].pointers[last]) break; + buffer[file->pos%blocksize]=*buf++; + ++file->pos; + if (file->ino->sizepos) file->ino->size=file->pos; + ++got; + --count; } - else for (last=14; last>=ptr; last-=2) + (void)writeBlock(file->ino->sb,block,buffer,start,end); + if (file->ino->sb->size<256) for (last=15; last>=0; --last) { - if (file->ino->sb->dir[extent].pointers[last] || file->ino->sb->dir[extent].pointers[last+1]) break; + if (file->ino->sb->dir[extent].pointers[last]) + { + break; + } } - if (last==ptr) /* we wrote the last used block of this extent */ + else for (last=14; last>0; last-=2) { - file->ino->sb->dir[extent].extnol=EXTENTL((file->pos-1)/16384); - file->ino->sb->dir[extent].extnoh=EXTENTH((file->pos-1)/16384); - file->ino->sb->dir[extent].blkcnt=((file->pos-1)%16384)/128+1; - file->ino->sb->dir[extent].lrc=file->pos%128; - writePhysDirectory(file->ino->sb); + if (file->ino->sb->dir[extent].pointers[last] || file->ino->sb->dir[extent].pointers[last+1]) + { + last/=2; + break; + } } + if (last>0) extentno+=(last*blocksize)/extcap; + file->ino->sb->dir[extent].extnol=EXTENTL(extentno); + file->ino->sb->dir[extent].extnoh=EXTENTH(extentno); + file->ino->sb->dir[extent].blkcnt=((file->pos-1)%16384)/128+1; + file->ino->sb->dir[extent].lrc=file->pos%128; + updateTimeStamps(file->ino,extent); + /*}}}*/ + if (file->pos==nextextpos) findext=1; + else if (file->pos==nextblockpos) findblock=1; } return got; } @@ -1370,7 +1430,6 @@ int cpmWrite(struct cpmFile *file, const char *buf, int count) /* cpmClose -- close */ /*{{{*/ int cpmClose(struct cpmFile *file) { - if (file->mode&O_WRONLY) return (writePhysDirectory(file->ino->sb)); return 0; } /*}}}*/ @@ -1396,6 +1455,7 @@ int cpmCreat(struct cpmInode *dir, const char *fname, struct cpmInode *ino, mode drive=dir->sb; if ((extent=findFreeExtent(dir->sb))==-1) return -1; ent=dir->sb->dir+extent; + drive->dirtyDirectory=1; memset(ent,0,32); ent->status=user; memcpy(ent->name,name,8); @@ -1408,15 +1468,14 @@ int cpmCreat(struct cpmInode *dir, const char *fname, struct cpmInode *ino, mode time(&ino->ctime); ino->sb=dir->sb; updateTimeStamps(ino,extent); - writePhysDirectory(dir->sb); return 0; } /*}}}*/ /* cpmAttrGet -- get CP/M attributes */ /*{{{*/ int cpmAttrGet(struct cpmInode *ino, cpm_attr_t *attrib) { - *attrib = ino->attr; - return 0; + *attrib = ino->attr; + return 0; } /*}}}*/ /* cpmAttrSet -- set CP/M attributes */ /*{{{*/ @@ -1432,6 +1491,7 @@ int cpmAttrSet(struct cpmInode *ino, cpm_attr_t attrib) drive = ino->sb; extent = ino->ino; + drive->dirtyDirectory=1; /* Strip off existing attribute bits */ memcpy7(name, drive->dir[extent].name, 8); memcpy7(extension, drive->dir[extent].ext, 3); @@ -1451,7 +1511,6 @@ int cpmAttrSet(struct cpmInode *ino, cpm_attr_t attrib) memcpy(drive->dir[extent].name, name, 8); memcpy(drive->dir[extent].ext, extension, 3); } while ((extent=findFileExtent(drive, user,name,extension,extent+1,-1))!=-1); - if (writePhysDirectory(drive)==-1) return -1; /* Update the stored (inode) copies of the file attributes and mode */ ino->attr=attrib; @@ -1467,19 +1526,33 @@ int cpmChmod(struct cpmInode *ino, mode_t mode) /* Convert the chmod() into a chattr() call that affects RO */ int newatt = ino->attr & ~CPM_ATTR_RO; - if ((mode & (S_IWUSR|S_IWGRP|S_IWOTH))) newatt |= CPM_ATTR_RO; + if (!(mode & (S_IWUSR|S_IWGRP|S_IWOTH))) newatt |= CPM_ATTR_RO; return cpmAttrSet(ino, newatt); } /*}}}*/ /* cpmSync -- write directory back */ /*{{{*/ -int cpmSync(struct cpmSuperBlock *sb) +int cpmSync(struct cpmSuperBlock *d) { - return (writePhysDirectory(sb)); + if (d->dirtyDirectory) + { + int i,blocks,entry; + + blocks=(d->maxdir*32+d->blksiz-1)/d->blksiz; + entry=0; + for (i=0; idir+entry),0,-1)==-1) return -1; + entry+=(d->blksiz/32); + } + d->dirtyDirectory=0; + } + return 0; } /*}}}*/ /* cpmUmount -- free super block */ /*{{{*/ void cpmUmount(struct cpmSuperBlock *sb) { + cpmSync(sb); free(sb->alv); free(sb->skewtab); free(sb->dir);