1 /* #includes */ /*{{{C}}}*//*{{{*/
22 const char cmd[]="cpmcp";
24 static int preserve=0;
27 * Return the user number.
28 * @param s CP/M filename in 0[0]:aaaaaaaa.bbb format.
29 * @returns The user number or -1 for no match.
31 static int userNumber(const char *s) /*{{{*/
33 if (isdigit(*s) && *(s+1)==':') return (*s-'0');
34 if (isdigit(*s) && isdigit(*(s+1)) && *(s+2)==':') return (10*(*s-'0')+(*(s+1)-'0'));
40 * Copy one file from CP/M to UNIX.
41 * @param root The inode for the root directory.
42 * @param src The CP/M filename in 00aaaaaaaabbb format.
43 * @param dest The UNIX filename.
44 * @returns 0 for success, 1 for error.
46 static int cpmToUnix(const struct cpmInode *root, const char *src, const char *dest) /*{{{*/
51 if (cpmNamei(root,src,&ino)==-1) { fprintf(stderr,"%s: can not open `%s': %s\n",cmd,src,boo); exitcode=1; }
57 cpmOpen(&ino,&file,O_RDONLY);
58 if ((ufp=fopen(dest,text ? "w" : "wb"))==(FILE*)0) { fprintf(stderr,"%s: can not create %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; }
66 while ((res=cpmRead(&file,buf,sizeof(buf)))>0)
74 if (buf[j]=='\032') goto endwhile;
79 if (putc('\n',ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
82 else if (putc('\r',ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
83 crpending=(buf[j]=='\r');
87 if (buf[j]=='\r') crpending=1;
88 else if (putc(buf[j],ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
91 else if (putc(buf[j],ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
95 if (res==-1 && !ohno) { fprintf(stderr,"%s: can not read %s (%s)\n",cmd,src,boo); exitcode=1; ohno=1; }
96 if (fclose(ufp)==EOF && !ohno) { fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; }
97 if (preserve && !ohno && (ino.atime || ino.mtime))
101 if (ino.atime) ut.actime=ino.atime; else time(&ut.actime);
102 if (ino.mtime) ut.modtime=ino.mtime; else time(&ut.modtime);
103 if (utime(dest,&ut)==-1) { fprintf(stderr,"%s: can change timestamps of %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; }
112 static void usage(void) /*{{{*/
114 fprintf(stderr,"Usage: %s [-f format] [-p] [-t] image user:file file\n",cmd);
115 fprintf(stderr," %s [-f format] [-p] [-t] image user:file ... directory\n",cmd);
116 fprintf(stderr," %s [-f format] [-p] [-t] image file user:file\n",cmd);
117 fprintf(stderr," %s [-f format] [-p] [-t] image file ... user:\n",cmd);
122 int main(int argc, char *argv[])
124 /* variables */ /*{{{*/
128 const char *devopts=NULL;
129 int c,readcpm=-1,todir=-1;
130 struct cpmInode root;
131 struct cpmSuperBlock super;
137 /* parse options */ /*{{{*/
138 if (!(format=getenv("CPMTOOLSFMT"))) format=FORMAT;
139 while ((c=getopt(argc,argv,"T:f:h?pt"))!=EOF) switch(c)
141 case 'T': devopts=optarg; break;
142 case 'f': format=optarg; break;
144 case '?': usage(); break;
145 case 'p': preserve=1; break;
146 case 't': text=1; break;
149 /* parse arguments */ /*{{{*/
150 if ((optind+2)>=argc) usage();
151 image=argv[optind++];
153 if (userNumber(argv[optind])>=0) /* cpm -> unix? */ /*{{{*/
158 for (i=optind; i<(argc-1); ++i) if (userNumber(argv[i])==-1) usage();
159 todir=((argc-optind)>2);
160 if (stat(argv[argc-1],&statbuf)==-1) { if (todir) usage(); }
161 else if (S_ISDIR(statbuf.st_mode)) todir=1; else if (todir) usage();
165 else if (userNumber(argv[argc-1])>=0) /* unix -> cpm */ /*{{{*/
170 for (i=optind; i<(argc-1); ++i) if (userNumber(argv[i])>=0) usage();
171 if ((argc-optind)>2 && *(strchr(argv[argc-1],':')+1)!='\0') usage();
172 if (*(strchr(argv[argc-1],':')+1)=='\0') todir=1;
178 /* open image file */ /*{{{*/
179 if ((err=Device_open(&super.dev,image,readcpm ? O_RDONLY : O_RDWR, devopts)))
181 fprintf(stderr,"%s: cannot open %s (%s)\n",cmd,image,err);
184 if (cpmReadSuper(&super,&root,format)==-1)
186 fprintf(stderr,"%s: cannot read superblock (%s)\n",cmd,boo);
190 if (readcpm) /* copy from CP/M to UNIX */ /*{{{*/
193 char *last=argv[argc-1];
195 cpmglob(optind,argc-1,argv,&root,&gargc,&gargv);
196 /* trying to copy multiple files to a file? */
197 if (gargc>1 && !todir) usage();
198 for (i=0; i<gargc; ++i)
200 char dest[_POSIX_PATH_MAX];
206 strcat(dest,gargv[i]+2);
208 else strcpy(dest,last);
209 if (cpmToUnix(&root,gargv[i],dest)) exitcode=1;
213 else /* copy from UNIX to CP/M */ /*{{{*/
217 for (i=optind; i<(argc-1); ++i)
219 /* variables */ /*{{{*/
224 if ((ufp=fopen(argv[i],"rb"))==(FILE*)0) /* cry a little */ /*{{{*/
226 fprintf(stderr,"%s: can not open %s: %s\n",cmd,argv[i],strerror(errno));
233 char cpmname[2+8+1+3+1]; /* 00foobarxy.zzy\0 */
240 if ((dest=strrchr(argv[i],'/'))!=(char*)0) ++dest; else dest=argv[i];
241 snprintf(cpmname,sizeof(cpmname),"%02d%s",userNumber(argv[argc-1]),dest);
245 snprintf(cpmname,sizeof(cpmname),"%02d%s",userNumber(argv[argc-1]),strchr(argv[argc-1],':')+1);
247 if (cpmCreat(&root,cpmname,&ino,0666)==-1) /* just cry */ /*{{{*/
249 fprintf(stderr,"%s: can not create %s: %s\n",cmd,cpmname,boo);
259 cpmOpen(&ino,&file,O_WRONLY);
264 for (j=0; j<(sizeof(buf)/2) && (c=getc(ufp))!=EOF; ++j)
266 if (text && c=='\n') buf[j++]='\r';
269 if (text && c==EOF) buf[j++]='\032';
270 if (cpmWrite(&file,buf,j)!=(ssize_t)j)
272 fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,boo);
278 if (cpmClose(&file)==EOF && !ohno) /* I just can't hold back the tears */ /*{{{*/
280 fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,boo);
284 if (preserve && !ohno)
286 struct utimbuf times;
287 times.actime=st.st_atime;
288 times.modtime=st.st_mtime;
289 cpmUtime(&ino,×);