/*}}}*/
/* 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; i<blocks; ++i)
- {
- if (readBlock(drive,i,(char*)(drive->dir+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; i<blocks; ++i)
- {
- if (writeBlock(drive,i,(char*)(drive->dir+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)
{
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 */ /*{{{*/
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)
d->skew=1;
d->extents=0;
d->type=CPMFS_DR3;
+ d->skewtab=(int*)0;
if (strcmp(argv[1],format)==0) found=1;
}
}
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;
if (strcmp(format, "amstrad")==0) amsReadSuper(d,format);
else diskdefReadSuper(d,format);
Device_setGeometry(&d->dev,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; i<d->sectrk; ++i,j=(j+d->skew)%d->sectrk)
{
while (1)
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; i<blocks; ++i)
+ {
+ if (readBlock(d,i,(char*)(d->dir+entry),0,-1)==-1) return -1;
+ entry+=(d->blksiz/32);
+ }
+ }
+ /*}}}*/
alvInit(d);
if (d->type==CPMFS_DR3) /* read additional superblock information */ /*{{{*/
{
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;
}
/*}}}*/
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;
}
}
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;
}
/*}}}*/
}
*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;
}
/*}}}*/
/* fill block and write it */ /*{{{*/
+ file->ino->sb->dirtyDirectory=1;
while (file->pos!=nextblockpos && count)
{
buffer[file->pos%blocksize]=*buf++;
if (file->pos==nextextpos) findext=1;
else if (file->pos==nextblockpos) findblock=1;
}
- writePhysDirectory(file->ino->sb);
return got;
}
/*}}}*/
/* cpmClose -- close */ /*{{{*/
int cpmClose(struct cpmFile *file)
{
- if (file->mode&O_WRONLY) return (writePhysDirectory(file->ino->sb));
return 0;
}
/*}}}*/
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);
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 */ /*{{{*/
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);
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;
}
/*}}}*/
/* 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; i<blocks; ++i)
+ {
+ if (writeBlock(d,i,(char*)(d->dir+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);