+ ino->sb->dirtyDs = 1;
+}
+/*}}}*/
+/* readTimeStamps -- read CP/M time stamp */ /*{{{*/
+static int readTimeStamps(struct cpmInode *i, int lowestExt)
+{
+ /* variables */ /*{{{*/
+ struct PhysDirectoryEntry *date;
+ int u_days=0,u_hour=0,u_min=0;
+ int ca_days=0,ca_hour=0,ca_min=0;
+ int protectMode=0;
+ /*}}}*/
+
+ if ( (i->sb->type&CPMFS_CPM3_DATES) && (date=i->sb->dir+(lowestExt|3))->status==0x21 )
+ {
+ switch (lowestExt&3)
+ {
+ case 0: /* first entry of the four */ /*{{{*/
+ {
+ ca_days=((unsigned char)date->name[0])+(((unsigned char)date->name[1])<<8);
+ ca_hour=(unsigned char)date->name[2];
+ ca_min=(unsigned char)date->name[3];
+ 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->ext[0];
+ break;
+ }
+ /*}}}*/
+ case 1: /* second entry */ /*{{{*/
+ {
+ ca_days=((unsigned char)date->ext[2])+(((unsigned char)date->extnol)<<8);
+ ca_hour=(unsigned char)date->lrc;
+ ca_min=(unsigned char)date->extnoh;
+ u_days=((unsigned char)date->blkcnt)+(((unsigned char)date->pointers[0])<<8);
+ u_hour=(unsigned char)date->pointers[1];
+ u_min=(unsigned char)date->pointers[2];
+ protectMode=(unsigned char)date->pointers[3];
+ break;
+ }
+ /*}}}*/
+ case 2: /* third one */ /*{{{*/
+ {
+ ca_days=((unsigned char)date->pointers[5])+(((unsigned char)date->pointers[6])<<8);
+ ca_hour=(unsigned char)date->pointers[7];
+ ca_min=(unsigned char)date->pointers[8];
+ u_days=((unsigned char)date->pointers[9])+(((unsigned char)date->pointers[10])<<8);
+ u_hour=(unsigned char)date->pointers[11];
+ u_min=(unsigned char)date->pointers[12];
+ protectMode=(unsigned char)date->pointers[13];
+ break;
+ }
+ /*}}}*/
+ }
+ if (i->sb->cnotatime)
+ {
+ i->ctime=cpm2unix_time(ca_days,ca_hour,ca_min);
+ i->atime=0;
+ }
+ else
+ {
+ i->ctime=0;
+ i->atime=cpm2unix_time(ca_days,ca_hour,ca_min);
+ }
+ i->mtime=cpm2unix_time(u_days,u_hour,u_min);
+ }
+ else
+ {
+ i->atime=i->mtime=i->ctime=0;
+ protectMode=0;
+ }
+
+ return protectMode;
+}
+/*}}}*/
+/* readDsStamps -- read datestamper time stamp */ /*{{{*/
+static void readDsStamps(struct cpmInode *i, int lowestExt)
+{
+ struct dsDate *stamp;
+
+ if ( !(i->sb->type&CPMFS_DS_DATES) ) return;
+
+ /* Get datestamp */
+ stamp = i->sb->ds+lowestExt;
+
+ i->mtime = ds2unix_time(&stamp->modify);
+ i->ctime = ds2unix_time(&stamp->create);
+ i->atime = ds2unix_time(&stamp->access);
+}
+/*}}}*/
+
+/* match -- match filename against a pattern */ /*{{{*/
+static int recmatch(char const *a, char const *pattern)
+{
+ int first=1;
+
+ assert(a);
+ assert(pattern);
+ while (*pattern)
+ {
+ switch (*pattern)
+ {
+ 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;
+ }
+ first=0;
+ }
+ return (*pattern=='\0' && *a=='\0');
+}
+
+int match(char const *a, char const *pattern)
+{
+ int user;
+ char pat[257];
+
+ assert(a);
+ assert(pattern);
+ assert(strlen(pattern)<255);
+ if (isdigit(*pattern) && *(pattern+1)==':') { user=(*pattern-'0'); pattern+=2; }
+ else if (isdigit(*pattern) && isdigit(*(pattern+1)) && *(pattern+2)==':') { user=(10*(*pattern-'0')+(*(pattern+1)-'0')); pattern+=3; }
+ else user=-1;
+ if (user==-1) sprintf(pat,"??%s",pattern);
+ else sprintf(pat,"%02d%s",user,pattern);
+ return recmatch(a,pat);
+}
+
+/*}}}*/
+/* cpmglob -- expand CP/M style wildcards */ /*{{{*/
+void cpmglob(int optin, int argc, char * const argv[], struct cpmInode *root, int *gargc, char ***gargv)
+{
+ struct cpmFile dir;
+ int entries,dirsize=0;
+ struct cpmDirent *dirent=(struct cpmDirent*)0;
+ int gargcap=0,i,j;
+
+ *gargv=(char**)0;
+ *gargc=0;
+ cpmOpendir(root,&dir);
+ entries=0;
+ 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; i<argc; ++i)
+ {
+ int found;
+
+ for (j=0,found=0; j<entries; ++j)
+ {
+ if (match(dirent[j].name,argv[i]))
+ {
+ if (*gargc==gargcap) *gargv=realloc(*gargv,sizeof(char*)*(gargcap ? (gargcap*=2) : (gargcap=16)));
+ (*gargv)[*gargc]=strcpy(malloc(strlen(dirent[j].name)+1),dirent[j].name);
+ ++*gargc;
+ ++found;
+ }
+ }
+ }
+ free(dirent);
+}
+/*}}}*/
+/* cpmglobfree -- free expanded wildcards */ /*{{{*/
+void cpmglobfree(char **dirent, int entries)
+{
+ int d;
+
+ assert(dirent);
+ assert(entries>=0);
+ for (d=0; d<entries; ++d) free(dirent[d]);
+ free(dirent);
+}
+/*}}}*/
+
+/* superblock management */