Imported Upstream version 2.17
[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)-'0'));
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;
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   if (!(format=getenv("CPMTOOLSFMT"))) format=FORMAT;
139   while ((c=getopt(argc,argv,"T:f:h?pt"))!=EOF) switch(c)
140   {
141     case 'T': devopts=optarg; break;
142     case 'f': format=optarg; break;
143     case 'h':
144     case '?': usage(); break;
145     case 'p': preserve=1; break;
146     case 't': text=1; break;
147   }
148   /*}}}*/
149   /* parse arguments */ /*{{{*/
150   if ((optind+2)>=argc) usage();
151   image=argv[optind++];
152
153   if (userNumber(argv[optind])>=0) /* cpm -> unix? */ /*{{{*/
154   {
155     int i;
156     struct stat statbuf;
157
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();
162     readcpm=1;
163   }
164   /*}}}*/
165   else if (userNumber(argv[argc-1])>=0) /* unix -> cpm */ /*{{{*/
166   {
167     int i;
168
169     todir=0;
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;
173     readcpm=0;
174   }
175   /*}}}*/
176   else usage();
177   /*}}}*/
178   /* open image file */ /*{{{*/
179   if ((err=Device_open(&super.dev,image,readcpm ? O_RDONLY : O_RDWR, devopts)))
180   {
181     fprintf(stderr,"%s: can not open %s (%s)\n",cmd,image,err);
182     exit(1);
183   }
184   cpmReadSuper(&super,&root,format);
185   /*}}}*/
186   if (readcpm) /* copy from CP/M to UNIX */ /*{{{*/
187   {
188     int i;
189     char *last=argv[argc-1];
190     
191     cpmglob(optind,argc-1,argv,&root,&gargc,&gargv);
192     /* trying to copy multiple files to a file? */
193     if (gargc>1 && !todir) usage();
194     for (i=0; i<gargc; ++i)
195     {
196       char dest[_POSIX_PATH_MAX];
197
198       if (todir)
199       {
200         strcpy(dest,last);
201         strcat(dest,"/");
202         strcat(dest,gargv[i]+2);
203       }
204       else strcpy(dest,last);
205       if (cpmToUnix(&root,gargv[i],dest)) exitcode=1;
206     }
207   }
208   /*}}}*/
209   else /* copy from UNIX to CP/M */ /*{{{*/
210   {
211     int i;
212
213     for (i=optind; i<(argc-1); ++i)
214     {
215       /* variables */ /*{{{*/
216       char *dest=(char*)0;
217       FILE *ufp;
218       /*}}}*/
219
220       if ((ufp=fopen(argv[i],"rb"))==(FILE*)0) /* cry a little */ /*{{{*/
221       {
222         fprintf(stderr,"%s: can not open %s: %s\n",cmd,argv[i],strerror(errno));
223         exitcode=1;
224       }
225       /*}}}*/
226       else
227       {
228         struct cpmInode ino;
229         char cpmname[2+8+1+3+1]; /* 00foobarxy.zzy\0 */
230         struct stat st;
231
232         stat(argv[i],&st);
233
234         if (todir)
235         {
236           if ((dest=strrchr(argv[i],'/'))!=(char*)0) ++dest; else dest=argv[i];
237           snprintf(cpmname,sizeof(cpmname),"%02d%s",userNumber(argv[argc-1]),dest);
238         }
239         else
240         {
241           snprintf(cpmname,sizeof(cpmname),"%02d%s",userNumber(argv[argc-1]),strchr(argv[argc-1],':')+1);
242         }
243         if (cpmCreat(&root,cpmname,&ino,0666)==-1) /* just cry */ /*{{{*/
244         {
245           fprintf(stderr,"%s: can not create %s: %s\n",cmd,cpmname,boo);
246           exitcode=1;
247         }
248         /*}}}*/
249         else
250         {
251           struct cpmFile file;
252           int ohno=0;
253           char buf[4096+1];
254
255           cpmOpen(&ino,&file,O_WRONLY);
256           do
257           {
258             int j;
259
260             for (j=0; j<(sizeof(buf)/2) && (c=getc(ufp))!=EOF; ++j)
261             {
262               if (text && c=='\n') buf[j++]='\r';
263               buf[j]=c;
264             }
265             if (text && c==EOF) buf[j++]='\032';
266             if (cpmWrite(&file,buf,j)!=j)
267             {
268               fprintf(stderr,"%s: can not write %s: %s\n",cmd,dest,boo);
269               ohno=1;
270               exitcode=1;
271               break;
272             }
273           } while (c!=EOF);
274           if (cpmClose(&file)==EOF && !ohno) /* I just can't hold back the tears */ /*{{{*/
275           {
276             fprintf(stderr,"%s: can not close %s: %s\n",cmd,dest,boo);
277             exitcode=1;
278           }
279           /*}}}*/
280           if (preserve && !ohno)
281           {
282             struct utimbuf times;
283             times.actime=st.st_atime;
284             times.modtime=st.st_mtime;
285             cpmUtime(&ino,&times);
286           }
287         }
288         fclose(ufp);
289       }
290     }
291   }
292   /*}}}*/
293   cpmUmount(&super);
294   exit(exitcode);
295 }