Imported Upstream version 2.10
[debian/cpmtools] / cpmcp.c
1 /* #includes */ /*{{{C}}}*//*{{{*/
2 #include "config.h"
3
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <ctype.h>
7 #include <errno.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <fcntl.h>
11 #include <limits.h>
12 #include <stdlib.h>
13 #include <utime.h>
14
15 #include "getopt_.h"
16 #include "cpmfs.h"
17
18 #ifdef USE_DMALLOC
19 #include <dmalloc.h>
20 #endif
21 /*}}}*/
22
23 const char cmd[]="cpmcp";
24 static int text=0;
25 static int preserve=0;
26
27 /**
28  * Return the user number.
29  * @param s CP/M filename in 0[0]:aaaaaaaa.bbb format.
30  * @returns The user number or -1 for no match.
31  */
32 static int userNumber(const char *s) /*{{{*/
33 {
34   if (isdigit(*s) && *(s+1)==':') return (*s-'0');
35   if (isdigit(*s) && isdigit(*(s+1)) && *(s+2)==':') return (10*(*s-'0')+(*(s+1)));
36   return -1;
37 }
38 /*}}}*/
39
40 /**
41  * Copy one file from CP/M to UNIX.
42  * @param root The inode for the root directory.
43  * @param src  The CP/M filename in 00aaaaaaaabbb format.
44  * @param dest The UNIX filename.
45  * @returns 0 for success, 1 for error.
46  */
47 static int cpmToUnix(const struct cpmInode *root, const char *src, const char *dest) /*{{{*/
48 {
49   struct cpmInode ino;
50   int exitcode=0;
51
52   if (cpmNamei(root,src,&ino)==-1) { fprintf(stderr,"%s: can not open `%s': %s\n",cmd,src,boo); exitcode=1; }
53   else
54   {
55     struct cpmFile file;
56     FILE *ufp;
57
58     cpmOpen(&ino,&file,O_RDONLY);
59     if ((ufp=fopen(dest,text ? "w" : "wb"))==(FILE*)0) { fprintf(stderr,"%s: can not create %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; }
60     else
61     {
62       int crpending=0;
63       int ohno=0;
64       int res;
65       char buf[4096];
66
67       while ((res=cpmRead(&file,buf,sizeof(buf)))!=0)
68       {
69         int j;
70
71         for (j=0; j<res; ++j)
72         {
73           if (text)
74           {
75             if (buf[j]=='\032') goto endwhile;
76             if (crpending)
77             {
78               if (buf[j]=='\n') 
79               {
80                 if (putc('\n',ufp)==EOF) { fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,strerror(errno)); exitcode=1; ohno=1; goto endwhile; }
81                 crpending=0;
82               }
83               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; }
84               crpending=(buf[j]=='\r');
85             }
86             else
87             {
88               if (buf[j]=='\r') crpending=1;
89               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; }
90             }
91           }
92           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; }
93         }
94       }
95       endwhile:
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))
98       {
99         struct utimbuf ut;
100
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; }
104       }
105     }
106     cpmClose(&file);
107   }
108   return exitcode;
109 }
110 /*}}}*/
111
112 static void usage(void) /*{{{*/
113 {
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);
118   exit(1);
119 }
120 /*}}}*/
121
122 int main(int argc, char *argv[])
123 {
124   /* variables */ /*{{{*/
125   const char *err;
126   const char *image;
127   const char *format=FORMAT;
128   const char *devopts=NULL;
129   int c,readcpm=-1,todir=-1;
130   struct cpmInode root;
131   struct cpmSuperBlock super;
132   int exitcode=0;
133   int gargc;
134   char **gargv;
135   /*}}}*/
136
137   /* parse options */ /*{{{*/
138   while ((c=getopt(argc,argv,"T:f:h?pt"))!=EOF) switch(c)
139   {
140     case 'T': devopts=optarg; break;
141     case 'f': format=optarg; break;
142     case 'h':
143     case '?': usage(); break;
144     case 'p': preserve=1; break;
145     case 't': text=1; break;
146   }
147   /*}}}*/
148   /* parse arguments */ /*{{{*/
149   if ((optind+2)>=argc) usage();
150   image=argv[optind++];
151
152   if (userNumber(argv[optind])>=0) /* cpm -> unix? */ /*{{{*/
153   {
154     int i;
155     struct stat statbuf;
156
157     for (i=optind; i<(argc-1); ++i) if (userNumber(argv[i])==-1) usage();
158     todir=((argc-optind)>2);
159     if (stat(argv[argc-1],&statbuf)==-1) { if (todir) usage(); }
160     else if (S_ISDIR(statbuf.st_mode)) todir=1; else if (todir) usage();
161     readcpm=1;
162   }
163   /*}}}*/
164   else if (userNumber(argv[argc-1])>=0) /* unix -> cpm */ /*{{{*/
165   {
166     int i;
167
168     todir=0;
169     for (i=optind; i<(argc-1); ++i) if (userNumber(argv[i])>=0) usage();
170     if ((argc-optind)>2 && *(strchr(argv[argc-1],':')+1)!='\0') usage();
171     if (*(strchr(argv[argc-1],':')+1)=='\0') todir=1;
172     readcpm=0;
173   }
174   /*}}}*/
175   else usage();
176   /*}}}*/
177   /* open image file */ /*{{{*/
178   if ((err=Device_open(&super.dev,image,readcpm ? O_RDONLY : O_RDWR, devopts)))
179   {
180     fprintf(stderr,"%s: can not open %s (%s)\n",cmd,image,err);
181     exit(1);
182   }
183   cpmReadSuper(&super,&root,format);
184   /*}}}*/
185   if (readcpm) /* copy from CP/M to UNIX */ /*{{{*/
186   {
187     int i;
188     char *last=argv[argc-1];
189     
190     cpmglob(optind,argc-1,argv,&root,&gargc,&gargv);
191     /* trying to copy multiple files to a file? */
192     if (gargc>1 && !todir) usage();
193     for (i=0; i<gargc; ++i)
194     {
195       char dest[_POSIX_PATH_MAX];
196
197       if (todir)
198       {
199         strcpy(dest,last);
200         strcat(dest,"/");
201         strcat(dest,gargv[i]+2);
202       }
203       else strcpy(dest,last);
204       if (cpmToUnix(&root,gargv[i],dest)) exitcode=1;
205     }
206   }
207   /*}}}*/
208   else /* copy from UNIX to CP/M */ /*{{{*/
209   {
210     int i;
211
212     for (i=optind; i<(argc-1); ++i)
213     {
214       /* variables */ /*{{{*/
215       char *dest=(char*)0;
216       FILE *ufp;
217       /*}}}*/
218
219       if ((ufp=fopen(argv[i],"r"))==(FILE*)0) /* cry a little */ /*{{{*/
220       {
221         fprintf(stderr,"%s: can not open %s: %s\n",cmd,argv[i],strerror(errno));
222         exitcode=1;
223       }
224       /*}}}*/
225       else
226       {
227         struct cpmInode ino;
228         char cpmname[2+8+3+1]; /* 00foobarxy.zzy\0 */
229
230         if (todir)
231         {
232           if ((dest=strrchr(argv[i],'/'))!=(char*)0) ++dest; else dest=argv[i];
233           sprintf(cpmname,"%02d%s",userNumber(argv[argc-1]),dest);
234         }
235         else
236         {
237           sprintf(cpmname,"%02d%s",userNumber(argv[argc-1]),strchr(argv[argc-1],':')+1);
238         }
239         if (cpmCreat(&root,cpmname,&ino,0666)==-1) /* just cry */ /*{{{*/
240         {
241           fprintf(stderr,"%s: can not create %s: %s\n",cmd,cpmname,boo);
242           exitcode=1;
243         }
244         /*}}}*/
245         else
246         {
247           struct cpmFile file;
248           int ohno=0;
249           char buf[4096+1];
250
251           cpmOpen(&ino,&file,O_WRONLY);
252           do
253           {
254             int j;
255
256             for (j=0; j<(sizeof(buf)/2) && (c=getc(ufp))!=EOF; ++j)
257             {
258               if (text && c=='\n') buf[j++]='\r';
259               buf[j]=c;
260             }
261             if (text && c==EOF) buf[j++]='\032';
262             if (cpmWrite(&file,buf,j)!=j)
263             {
264               fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,boo);
265               ohno=1;
266               exitcode=1;
267               break;
268             }
269           } while (c!=EOF);
270           if (cpmClose(&file)==EOF && !ohno) /* I just can't hold back the tears */ /*{{{*/
271           {
272             fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,boo);
273             exitcode=1;
274           }
275           /*}}}*/
276         }
277         fclose(ufp);
278       }
279     }
280   }
281   /*}}}*/
282   cpmUmount(&super);
283   exit(exitcode);
284 }