1*d5c9a868SElliott Hughes /* Copyright 1997-2002,2005-2009 Alain Knaff.
2*d5c9a868SElliott Hughes * This file is part of mtools.
3*d5c9a868SElliott Hughes *
4*d5c9a868SElliott Hughes * Mtools is free software: you can redistribute it and/or modify
5*d5c9a868SElliott Hughes * it under the terms of the GNU General Public License as published by
6*d5c9a868SElliott Hughes * the Free Software Foundation, either version 3 of the License, or
7*d5c9a868SElliott Hughes * (at your option) any later version.
8*d5c9a868SElliott Hughes *
9*d5c9a868SElliott Hughes * Mtools is distributed in the hope that it will be useful,
10*d5c9a868SElliott Hughes * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*d5c9a868SElliott Hughes * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12*d5c9a868SElliott Hughes * GNU General Public License for more details.
13*d5c9a868SElliott Hughes *
14*d5c9a868SElliott Hughes * You should have received a copy of the GNU General Public License
15*d5c9a868SElliott Hughes * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
16*d5c9a868SElliott Hughes *
17*d5c9a868SElliott Hughes * mainloop.c
18*d5c9a868SElliott Hughes * Iterating over all the command line parameters, and matching patterns
19*d5c9a868SElliott Hughes * where needed
20*d5c9a868SElliott Hughes */
21*d5c9a868SElliott Hughes
22*d5c9a868SElliott Hughes #include "sysincludes.h"
23*d5c9a868SElliott Hughes #include "msdos.h"
24*d5c9a868SElliott Hughes #include "mtools.h"
25*d5c9a868SElliott Hughes #include "vfat.h"
26*d5c9a868SElliott Hughes #include "fs.h"
27*d5c9a868SElliott Hughes #include "mainloop.h"
28*d5c9a868SElliott Hughes #include "plain_io.h"
29*d5c9a868SElliott Hughes #include "file.h"
30*d5c9a868SElliott Hughes #include "file_name.h"
31*d5c9a868SElliott Hughes
32*d5c9a868SElliott Hughes
33*d5c9a868SElliott Hughes /* Fix the info in the MCWD file to be a proper directory name.
34*d5c9a868SElliott Hughes * Always has a leading separator. Never has a trailing separator
35*d5c9a868SElliott Hughes * (unless it is the path itself). */
36*d5c9a868SElliott Hughes
fix_mcwd(char * ans)37*d5c9a868SElliott Hughes static const char *fix_mcwd(char *ans)
38*d5c9a868SElliott Hughes {
39*d5c9a868SElliott Hughes FILE *fp;
40*d5c9a868SElliott Hughes char *s;
41*d5c9a868SElliott Hughes char buf[MAX_PATH];
42*d5c9a868SElliott Hughes
43*d5c9a868SElliott Hughes fp = open_mcwd("r");
44*d5c9a868SElliott Hughes if(!fp || !fgets(buf, MAX_PATH, fp)) {
45*d5c9a868SElliott Hughes if(fp)
46*d5c9a868SElliott Hughes fclose(fp);
47*d5c9a868SElliott Hughes ans[0] = get_default_drive();
48*d5c9a868SElliott Hughes strcpy(ans+1, ":/");
49*d5c9a868SElliott Hughes return ans;
50*d5c9a868SElliott Hughes }
51*d5c9a868SElliott Hughes
52*d5c9a868SElliott Hughes buf[strlen(buf) -1] = '\0';
53*d5c9a868SElliott Hughes fclose(fp);
54*d5c9a868SElliott Hughes /* drive letter present? */
55*d5c9a868SElliott Hughes s = buf;
56*d5c9a868SElliott Hughes if (buf[0] && buf[1] == ':') {
57*d5c9a868SElliott Hughes memcpy(ans, buf, 2);
58*d5c9a868SElliott Hughes ans[2] = '\0';
59*d5c9a868SElliott Hughes s = &buf[2];
60*d5c9a868SElliott Hughes } else {
61*d5c9a868SElliott Hughes ans[0] = get_default_drive();
62*d5c9a868SElliott Hughes strcpy(ans+1, ":");
63*d5c9a868SElliott Hughes }
64*d5c9a868SElliott Hughes /* add a leading separator */
65*d5c9a868SElliott Hughes if (*s != '/' && *s != '\\') {
66*d5c9a868SElliott Hughes strcat(ans, "/");
67*d5c9a868SElliott Hughes strcat(ans, s);
68*d5c9a868SElliott Hughes } else
69*d5c9a868SElliott Hughes strcat(ans, s);
70*d5c9a868SElliott Hughes
71*d5c9a868SElliott Hughes #if 0
72*d5c9a868SElliott Hughes /* translate to upper case */
73*d5c9a868SElliott Hughes for (s = ans; *s; ++s) {
74*d5c9a868SElliott Hughes *s = ch_toupper(*s);
75*d5c9a868SElliott Hughes if (*s == '\\')
76*d5c9a868SElliott Hughes *s = '/';
77*d5c9a868SElliott Hughes }
78*d5c9a868SElliott Hughes #endif
79*d5c9a868SElliott Hughes /* if only drive, colon, & separator */
80*d5c9a868SElliott Hughes if (strlen(ans) == 3)
81*d5c9a868SElliott Hughes return(ans);
82*d5c9a868SElliott Hughes /* zap the trailing separator */
83*d5c9a868SElliott Hughes if (*--s == '/')
84*d5c9a868SElliott Hughes *s = '\0';
85*d5c9a868SElliott Hughes return ans;
86*d5c9a868SElliott Hughes }
87*d5c9a868SElliott Hughes
88*d5c9a868SElliott Hughes int unix_dir_loop(Stream_t *Stream, MainParam_t *mp);
89*d5c9a868SElliott Hughes int unix_loop(Stream_t *Stream UNUSEDP, MainParam_t *mp, char *arg,
90*d5c9a868SElliott Hughes int follow_dir_link);
91*d5c9a868SElliott Hughes
_unix_loop(Stream_t * Dir,MainParam_t * mp,const char * filename UNUSEDP)92*d5c9a868SElliott Hughes static int _unix_loop(Stream_t *Dir, MainParam_t *mp,
93*d5c9a868SElliott Hughes const char *filename UNUSEDP)
94*d5c9a868SElliott Hughes {
95*d5c9a868SElliott Hughes return unix_dir_loop(Dir, mp);
96*d5c9a868SElliott Hughes }
97*d5c9a868SElliott Hughes
unix_loop(Stream_t * Stream UNUSEDP,MainParam_t * mp,char * arg,int follow_dir_link)98*d5c9a868SElliott Hughes int unix_loop(Stream_t *Stream UNUSEDP, MainParam_t *mp,
99*d5c9a868SElliott Hughes char *arg, int follow_dir_link)
100*d5c9a868SElliott Hughes {
101*d5c9a868SElliott Hughes int ret;
102*d5c9a868SElliott Hughes int isdir=0;
103*d5c9a868SElliott Hughes size_t unixNameLength;
104*d5c9a868SElliott Hughes
105*d5c9a868SElliott Hughes mp->File = NULL;
106*d5c9a868SElliott Hughes mp->direntry = NULL;
107*d5c9a868SElliott Hughes unixNameLength = strlen(arg);
108*d5c9a868SElliott Hughes if(unixNameLength > 1 && arg[unixNameLength-1] == '/') {
109*d5c9a868SElliott Hughes /* names ending in slash, and having at least two characters */
110*d5c9a868SElliott Hughes char *name = strdup(arg);
111*d5c9a868SElliott Hughes name[unixNameLength-1]='\0';
112*d5c9a868SElliott Hughes mp->unixSourceName = name;
113*d5c9a868SElliott Hughes } else {
114*d5c9a868SElliott Hughes mp->unixSourceName = arg;
115*d5c9a868SElliott Hughes }
116*d5c9a868SElliott Hughes /* mp->dir.attr = ATTR_ARCHIVE;*/
117*d5c9a868SElliott Hughes mp->loop = _unix_loop;
118*d5c9a868SElliott Hughes if((mp->lookupflags & DO_OPEN)){
119*d5c9a868SElliott Hughes mp->File = SimpleFileOpen(0, 0, arg, O_RDONLY, 0, 0, 0, 0);
120*d5c9a868SElliott Hughes if(!mp->File){
121*d5c9a868SElliott Hughes perror(arg);
122*d5c9a868SElliott Hughes #if 0
123*d5c9a868SElliott Hughes tmp = _basename(arg);
124*d5c9a868SElliott Hughes strncpy(mp->filename, tmp, VBUFSIZE);
125*d5c9a868SElliott Hughes mp->filename[VBUFSIZE-1] = '\0';
126*d5c9a868SElliott Hughes #endif
127*d5c9a868SElliott Hughes return ERROR_ONE;
128*d5c9a868SElliott Hughes }
129*d5c9a868SElliott Hughes GET_DATA(mp->File, 0, 0, &isdir, 0);
130*d5c9a868SElliott Hughes if(isdir) {
131*d5c9a868SElliott Hughes #if !defined(__EMX__) && !defined(OS_mingw32msvc)
132*d5c9a868SElliott Hughes struct MT_STAT buf;
133*d5c9a868SElliott Hughes #endif
134*d5c9a868SElliott Hughes
135*d5c9a868SElliott Hughes FREE(&mp->File);
136*d5c9a868SElliott Hughes #if !defined(__EMX__) && !defined(OS_mingw32msvc)
137*d5c9a868SElliott Hughes if(!follow_dir_link &&
138*d5c9a868SElliott Hughes MT_LSTAT(arg, &buf) == 0 &&
139*d5c9a868SElliott Hughes S_ISLNK(buf.st_mode)) {
140*d5c9a868SElliott Hughes /* skip links to directories in order to avoid
141*d5c9a868SElliott Hughes * infinite loops */
142*d5c9a868SElliott Hughes fprintf(stderr,
143*d5c9a868SElliott Hughes "skipping directory symlink %s\n",
144*d5c9a868SElliott Hughes arg);
145*d5c9a868SElliott Hughes return 0;
146*d5c9a868SElliott Hughes }
147*d5c9a868SElliott Hughes #endif
148*d5c9a868SElliott Hughes if(! (mp->lookupflags & ACCEPT_DIR))
149*d5c9a868SElliott Hughes return 0;
150*d5c9a868SElliott Hughes mp->File = OpenDir(arg);
151*d5c9a868SElliott Hughes }
152*d5c9a868SElliott Hughes }
153*d5c9a868SElliott Hughes
154*d5c9a868SElliott Hughes if(isdir)
155*d5c9a868SElliott Hughes ret = mp->dirCallback(0, mp);
156*d5c9a868SElliott Hughes else
157*d5c9a868SElliott Hughes ret = mp->unixcallback(mp);
158*d5c9a868SElliott Hughes FREE(&mp->File);
159*d5c9a868SElliott Hughes return ret;
160*d5c9a868SElliott Hughes }
161*d5c9a868SElliott Hughes
162*d5c9a868SElliott Hughes
isSpecial(const char * name)163*d5c9a868SElliott Hughes int isSpecial(const char *name)
164*d5c9a868SElliott Hughes {
165*d5c9a868SElliott Hughes if(name[0] == '\0')
166*d5c9a868SElliott Hughes return 1;
167*d5c9a868SElliott Hughes if(!strcmp(name,"."))
168*d5c9a868SElliott Hughes return 1;
169*d5c9a868SElliott Hughes if(!strcmp(name,".."))
170*d5c9a868SElliott Hughes return 1;
171*d5c9a868SElliott Hughes return 0;
172*d5c9a868SElliott Hughes }
173*d5c9a868SElliott Hughes
174*d5c9a868SElliott Hughes #ifdef HAVE_WCHAR_H
isSpecialW(const wchar_t * name)175*d5c9a868SElliott Hughes int isSpecialW(const wchar_t *name)
176*d5c9a868SElliott Hughes {
177*d5c9a868SElliott Hughes if(name[0] == '\0')
178*d5c9a868SElliott Hughes return 1;
179*d5c9a868SElliott Hughes if(!wcscmp(name,L"."))
180*d5c9a868SElliott Hughes return 1;
181*d5c9a868SElliott Hughes if(!wcscmp(name,L".."))
182*d5c9a868SElliott Hughes return 1;
183*d5c9a868SElliott Hughes return 0;
184*d5c9a868SElliott Hughes }
185*d5c9a868SElliott Hughes #endif
186*d5c9a868SElliott Hughes
checkForDot(int lookupflags,const wchar_t * name)187*d5c9a868SElliott Hughes static int checkForDot(int lookupflags, const wchar_t *name)
188*d5c9a868SElliott Hughes {
189*d5c9a868SElliott Hughes return (lookupflags & NO_DOTS) && isSpecialW(name);
190*d5c9a868SElliott Hughes }
191*d5c9a868SElliott Hughes
192*d5c9a868SElliott Hughes
193*d5c9a868SElliott Hughes typedef struct lookupState_t {
194*d5c9a868SElliott Hughes Stream_t *container;
195*d5c9a868SElliott Hughes int nbContainers;
196*d5c9a868SElliott Hughes Stream_t *Dir;
197*d5c9a868SElliott Hughes int nbDirs;
198*d5c9a868SElliott Hughes const char *filename;
199*d5c9a868SElliott Hughes } lookupState_t;
200*d5c9a868SElliott Hughes
isUniqueTarget(const char * name)201*d5c9a868SElliott Hughes static int isUniqueTarget(const char *name)
202*d5c9a868SElliott Hughes {
203*d5c9a868SElliott Hughes return name && strcmp(name, "-");
204*d5c9a868SElliott Hughes }
205*d5c9a868SElliott Hughes
handle_leaf(direntry_t * direntry,MainParam_t * mp,lookupState_t * lookupState)206*d5c9a868SElliott Hughes static int handle_leaf(direntry_t *direntry, MainParam_t *mp,
207*d5c9a868SElliott Hughes lookupState_t *lookupState)
208*d5c9a868SElliott Hughes {
209*d5c9a868SElliott Hughes Stream_t *MyFile=0;
210*d5c9a868SElliott Hughes int ret;
211*d5c9a868SElliott Hughes
212*d5c9a868SElliott Hughes if(got_signal)
213*d5c9a868SElliott Hughes return ERROR_ONE;
214*d5c9a868SElliott Hughes if(lookupState) {
215*d5c9a868SElliott Hughes /* we are looking for a "target" file */
216*d5c9a868SElliott Hughes switch(lookupState->nbDirs) {
217*d5c9a868SElliott Hughes case 0: /* no directory yet, open it */
218*d5c9a868SElliott Hughes lookupState->Dir = OpenFileByDirentry(direntry);
219*d5c9a868SElliott Hughes lookupState->nbDirs++;
220*d5c9a868SElliott Hughes /* dump the container, we have
221*d5c9a868SElliott Hughes * better now */
222*d5c9a868SElliott Hughes FREE(&lookupState->container);
223*d5c9a868SElliott Hughes return 0;
224*d5c9a868SElliott Hughes case 1: /* we have already a directory */
225*d5c9a868SElliott Hughes FREE(&lookupState->Dir);
226*d5c9a868SElliott Hughes fprintf(stderr,"Ambiguous\n");
227*d5c9a868SElliott Hughes return STOP_NOW | ERROR_ONE;
228*d5c9a868SElliott Hughes default:
229*d5c9a868SElliott Hughes return STOP_NOW | ERROR_ONE;
230*d5c9a868SElliott Hughes }
231*d5c9a868SElliott Hughes }
232*d5c9a868SElliott Hughes
233*d5c9a868SElliott Hughes mp->direntry = direntry;
234*d5c9a868SElliott Hughes if(IS_DIR(direntry)) {
235*d5c9a868SElliott Hughes if(mp->lookupflags & (DO_OPEN | DO_OPEN_DIRS))
236*d5c9a868SElliott Hughes MyFile = mp->File = OpenFileByDirentry(direntry);
237*d5c9a868SElliott Hughes ret = mp->dirCallback(direntry, mp);
238*d5c9a868SElliott Hughes } else {
239*d5c9a868SElliott Hughes if(mp->lookupflags & DO_OPEN)
240*d5c9a868SElliott Hughes MyFile = mp->File = OpenFileByDirentry(direntry);
241*d5c9a868SElliott Hughes ret = mp->callback(direntry, mp);
242*d5c9a868SElliott Hughes }
243*d5c9a868SElliott Hughes FREE(&MyFile);
244*d5c9a868SElliott Hughes if(isUniqueTarget(mp->targetName))
245*d5c9a868SElliott Hughes ret |= STOP_NOW;
246*d5c9a868SElliott Hughes return ret;
247*d5c9a868SElliott Hughes }
248*d5c9a868SElliott Hughes
_dos_loop(Stream_t * Dir,MainParam_t * mp,const char * filename)249*d5c9a868SElliott Hughes static int _dos_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
250*d5c9a868SElliott Hughes {
251*d5c9a868SElliott Hughes Stream_t *MyFile=0;
252*d5c9a868SElliott Hughes direntry_t entry;
253*d5c9a868SElliott Hughes int ret;
254*d5c9a868SElliott Hughes int r;
255*d5c9a868SElliott Hughes
256*d5c9a868SElliott Hughes ret = 0;
257*d5c9a868SElliott Hughes r=0;
258*d5c9a868SElliott Hughes initializeDirentry(&entry, Dir);
259*d5c9a868SElliott Hughes while(!got_signal &&
260*d5c9a868SElliott Hughes (r=vfat_lookup_zt(&entry, filename,
261*d5c9a868SElliott Hughes mp->lookupflags,
262*d5c9a868SElliott Hughes mp->shortname.data, mp->shortname.len,
263*d5c9a868SElliott Hughes mp->longname.data, mp->longname.len)) == 0 ){
264*d5c9a868SElliott Hughes mp->File = NULL;
265*d5c9a868SElliott Hughes if(!checkForDot(mp->lookupflags,entry.name)) {
266*d5c9a868SElliott Hughes MyFile = 0;
267*d5c9a868SElliott Hughes if((mp->lookupflags & DO_OPEN) ||
268*d5c9a868SElliott Hughes (IS_DIR(&entry) &&
269*d5c9a868SElliott Hughes (mp->lookupflags & DO_OPEN_DIRS))) {
270*d5c9a868SElliott Hughes MyFile = mp->File = OpenFileByDirentry(&entry);
271*d5c9a868SElliott Hughes }
272*d5c9a868SElliott Hughes if(got_signal)
273*d5c9a868SElliott Hughes break;
274*d5c9a868SElliott Hughes mp->direntry = &entry;
275*d5c9a868SElliott Hughes if(IS_DIR(&entry))
276*d5c9a868SElliott Hughes ret |= mp->dirCallback(&entry,mp);
277*d5c9a868SElliott Hughes else
278*d5c9a868SElliott Hughes ret |= mp->callback(&entry, mp);
279*d5c9a868SElliott Hughes FREE(&MyFile);
280*d5c9a868SElliott Hughes }
281*d5c9a868SElliott Hughes if (fat_error(Dir))
282*d5c9a868SElliott Hughes ret |= ERROR_ONE;
283*d5c9a868SElliott Hughes if(mp->fast_quit && (ret & ERROR_ONE))
284*d5c9a868SElliott Hughes break;
285*d5c9a868SElliott Hughes }
286*d5c9a868SElliott Hughes if (r == -2)
287*d5c9a868SElliott Hughes return ERROR_ONE;
288*d5c9a868SElliott Hughes if(got_signal)
289*d5c9a868SElliott Hughes ret |= ERROR_ONE;
290*d5c9a868SElliott Hughes return ret;
291*d5c9a868SElliott Hughes }
292*d5c9a868SElliott Hughes
recurs_dos_loop(MainParam_t * mp,const char * filename0,const char * filename1,lookupState_t * lookupState)293*d5c9a868SElliott Hughes static int recurs_dos_loop(MainParam_t *mp, const char *filename0,
294*d5c9a868SElliott Hughes const char *filename1,
295*d5c9a868SElliott Hughes lookupState_t *lookupState)
296*d5c9a868SElliott Hughes {
297*d5c9a868SElliott Hughes /* Dir is de-allocated by the same entity which allocated it */
298*d5c9a868SElliott Hughes const char *ptr;
299*d5c9a868SElliott Hughes direntry_t entry;
300*d5c9a868SElliott Hughes size_t length;
301*d5c9a868SElliott Hughes int lookupflags;
302*d5c9a868SElliott Hughes int ret;
303*d5c9a868SElliott Hughes int have_one;
304*d5c9a868SElliott Hughes int doing_mcwd;
305*d5c9a868SElliott Hughes int r;
306*d5c9a868SElliott Hughes
307*d5c9a868SElliott Hughes while(1) {
308*d5c9a868SElliott Hughes /* strip dots and / */
309*d5c9a868SElliott Hughes if(!strncmp(filename0,"./", 2)) {
310*d5c9a868SElliott Hughes filename0 += 2;
311*d5c9a868SElliott Hughes continue;
312*d5c9a868SElliott Hughes }
313*d5c9a868SElliott Hughes if(!strcmp(filename0,".") && filename1) {
314*d5c9a868SElliott Hughes filename0 ++;
315*d5c9a868SElliott Hughes continue;
316*d5c9a868SElliott Hughes }
317*d5c9a868SElliott Hughes if(filename0[0] == '/') {
318*d5c9a868SElliott Hughes filename0++;
319*d5c9a868SElliott Hughes continue;
320*d5c9a868SElliott Hughes }
321*d5c9a868SElliott Hughes if(!filename0[0]) {
322*d5c9a868SElliott Hughes if(!filename1)
323*d5c9a868SElliott Hughes break;
324*d5c9a868SElliott Hughes filename0 = filename1;
325*d5c9a868SElliott Hughes filename1 = 0;
326*d5c9a868SElliott Hughes continue;
327*d5c9a868SElliott Hughes }
328*d5c9a868SElliott Hughes break;
329*d5c9a868SElliott Hughes }
330*d5c9a868SElliott Hughes
331*d5c9a868SElliott Hughes if(!strncmp(filename0,"../", 3) ||
332*d5c9a868SElliott Hughes (!strcmp(filename0, "..") && filename1)) {
333*d5c9a868SElliott Hughes /* up one level */
334*d5c9a868SElliott Hughes mp->File = getDirentry(mp->File)->Dir;
335*d5c9a868SElliott Hughes return recurs_dos_loop(mp, filename0+2, filename1, lookupState);
336*d5c9a868SElliott Hughes }
337*d5c9a868SElliott Hughes
338*d5c9a868SElliott Hughes doing_mcwd = !!filename1;
339*d5c9a868SElliott Hughes
340*d5c9a868SElliott Hughes ptr = strchr(filename0, '/');
341*d5c9a868SElliott Hughes if(!ptr) {
342*d5c9a868SElliott Hughes length = strlen(filename0);
343*d5c9a868SElliott Hughes ptr = filename1;
344*d5c9a868SElliott Hughes filename1 = 0;
345*d5c9a868SElliott Hughes } else {
346*d5c9a868SElliott Hughes length = ptrdiff(ptr, filename0);
347*d5c9a868SElliott Hughes ptr++;
348*d5c9a868SElliott Hughes }
349*d5c9a868SElliott Hughes if(!ptr) {
350*d5c9a868SElliott Hughes if(mp->lookupflags & OPEN_PARENT) {
351*d5c9a868SElliott Hughes mp->targetName = filename0;
352*d5c9a868SElliott Hughes ret = handle_leaf(getDirentry(mp->File), mp,
353*d5c9a868SElliott Hughes lookupState);
354*d5c9a868SElliott Hughes mp->targetName = 0;
355*d5c9a868SElliott Hughes return ret;
356*d5c9a868SElliott Hughes }
357*d5c9a868SElliott Hughes
358*d5c9a868SElliott Hughes if(!strcmp(filename0, ".") || !filename0[0]) {
359*d5c9a868SElliott Hughes return handle_leaf(getDirentry(mp->File),
360*d5c9a868SElliott Hughes mp, lookupState);
361*d5c9a868SElliott Hughes }
362*d5c9a868SElliott Hughes
363*d5c9a868SElliott Hughes if(!strcmp(filename0, "..")) {
364*d5c9a868SElliott Hughes return handle_leaf(getParent(getDirentry(mp->File)), mp,
365*d5c9a868SElliott Hughes lookupState);
366*d5c9a868SElliott Hughes }
367*d5c9a868SElliott Hughes
368*d5c9a868SElliott Hughes lookupflags = mp->lookupflags;
369*d5c9a868SElliott Hughes
370*d5c9a868SElliott Hughes if(lookupState) {
371*d5c9a868SElliott Hughes lookupState->filename = filename0;
372*d5c9a868SElliott Hughes if(lookupState->nbContainers + lookupState->nbDirs > 0){
373*d5c9a868SElliott Hughes /* we have already one target, don't bother
374*d5c9a868SElliott Hughes * with this one. */
375*d5c9a868SElliott Hughes FREE(&lookupState->container);
376*d5c9a868SElliott Hughes } else {
377*d5c9a868SElliott Hughes /* no match yet. Remember this container for
378*d5c9a868SElliott Hughes * later use */
379*d5c9a868SElliott Hughes lookupState->container = COPY(mp->File);
380*d5c9a868SElliott Hughes }
381*d5c9a868SElliott Hughes lookupState->nbContainers++;
382*d5c9a868SElliott Hughes }
383*d5c9a868SElliott Hughes } else
384*d5c9a868SElliott Hughes lookupflags = ACCEPT_DIR | DO_OPEN | NO_DOTS;
385*d5c9a868SElliott Hughes
386*d5c9a868SElliott Hughes ret = 0;
387*d5c9a868SElliott Hughes r = 0;
388*d5c9a868SElliott Hughes have_one = 0;
389*d5c9a868SElliott Hughes initializeDirentry(&entry, mp->File);
390*d5c9a868SElliott Hughes while(!(ret & STOP_NOW) &&
391*d5c9a868SElliott Hughes !got_signal &&
392*d5c9a868SElliott Hughes (r=vfat_lookup(&entry, filename0, length,
393*d5c9a868SElliott Hughes lookupflags | NO_MSG,
394*d5c9a868SElliott Hughes mp->shortname.data, mp->shortname.len,
395*d5c9a868SElliott Hughes mp->longname.data, mp->longname.len)) == 0 ){
396*d5c9a868SElliott Hughes if(checkForDot(lookupflags, entry.name))
397*d5c9a868SElliott Hughes /* while following the path, ignore the
398*d5c9a868SElliott Hughes * special entries if they were not
399*d5c9a868SElliott Hughes * explicitly given */
400*d5c9a868SElliott Hughes continue;
401*d5c9a868SElliott Hughes have_one = 1;
402*d5c9a868SElliott Hughes if(ptr) {
403*d5c9a868SElliott Hughes Stream_t *SubDir;
404*d5c9a868SElliott Hughes SubDir = mp->File = OpenFileByDirentry(&entry);
405*d5c9a868SElliott Hughes ret |= recurs_dos_loop(mp, ptr, filename1, lookupState);
406*d5c9a868SElliott Hughes FREE(&SubDir);
407*d5c9a868SElliott Hughes } else {
408*d5c9a868SElliott Hughes ret |= handle_leaf(&entry, mp, lookupState);
409*d5c9a868SElliott Hughes if(isUniqueTarget(mp->targetName))
410*d5c9a868SElliott Hughes return ret | STOP_NOW;
411*d5c9a868SElliott Hughes }
412*d5c9a868SElliott Hughes if(doing_mcwd)
413*d5c9a868SElliott Hughes break;
414*d5c9a868SElliott Hughes }
415*d5c9a868SElliott Hughes if (r == -2)
416*d5c9a868SElliott Hughes return ERROR_ONE;
417*d5c9a868SElliott Hughes if(got_signal)
418*d5c9a868SElliott Hughes return ret | ERROR_ONE;
419*d5c9a868SElliott Hughes if(doing_mcwd && !have_one)
420*d5c9a868SElliott Hughes return NO_CWD;
421*d5c9a868SElliott Hughes return ret;
422*d5c9a868SElliott Hughes }
423*d5c9a868SElliott Hughes
common_dos_loop(MainParam_t * mp,const char * pathname,lookupState_t * lookupState,int open_mode)424*d5c9a868SElliott Hughes static int common_dos_loop(MainParam_t *mp, const char *pathname,
425*d5c9a868SElliott Hughes lookupState_t *lookupState, int open_mode)
426*d5c9a868SElliott Hughes
427*d5c9a868SElliott Hughes {
428*d5c9a868SElliott Hughes Stream_t *RootDir;
429*d5c9a868SElliott Hughes const char *cwd;
430*d5c9a868SElliott Hughes char drive;
431*d5c9a868SElliott Hughes
432*d5c9a868SElliott Hughes int ret;
433*d5c9a868SElliott Hughes mp->loop = _dos_loop;
434*d5c9a868SElliott Hughes
435*d5c9a868SElliott Hughes drive='\0';
436*d5c9a868SElliott Hughes cwd = "";
437*d5c9a868SElliott Hughes if(*pathname && pathname[1] == ':') {
438*d5c9a868SElliott Hughes drive = ch_toupper(*pathname);
439*d5c9a868SElliott Hughes pathname += 2;
440*d5c9a868SElliott Hughes if(mp->mcwd[0] == drive)
441*d5c9a868SElliott Hughes cwd = mp->mcwd+2;
442*d5c9a868SElliott Hughes } else if(mp->mcwd[0]) {
443*d5c9a868SElliott Hughes drive = mp->mcwd[0];
444*d5c9a868SElliott Hughes cwd = mp->mcwd+2;
445*d5c9a868SElliott Hughes } else {
446*d5c9a868SElliott Hughes drive = get_default_drive();
447*d5c9a868SElliott Hughes }
448*d5c9a868SElliott Hughes
449*d5c9a868SElliott Hughes if(*pathname=='/') /* absolute path name */
450*d5c9a868SElliott Hughes cwd = "";
451*d5c9a868SElliott Hughes
452*d5c9a868SElliott Hughes RootDir = mp->File = open_root_dir(drive, open_mode, NULL);
453*d5c9a868SElliott Hughes if(!mp->File)
454*d5c9a868SElliott Hughes return ERROR_ONE;
455*d5c9a868SElliott Hughes
456*d5c9a868SElliott Hughes ret = recurs_dos_loop(mp, cwd, pathname, lookupState);
457*d5c9a868SElliott Hughes if(ret & NO_CWD) {
458*d5c9a868SElliott Hughes /* no CWD */
459*d5c9a868SElliott Hughes *mp->mcwd = '\0';
460*d5c9a868SElliott Hughes unlink_mcwd();
461*d5c9a868SElliott Hughes ret = recurs_dos_loop(mp, "", pathname, lookupState);
462*d5c9a868SElliott Hughes }
463*d5c9a868SElliott Hughes FREE(&RootDir);
464*d5c9a868SElliott Hughes return ret;
465*d5c9a868SElliott Hughes }
466*d5c9a868SElliott Hughes
dos_loop(MainParam_t * mp,const char * arg)467*d5c9a868SElliott Hughes static int dos_loop(MainParam_t *mp, const char *arg)
468*d5c9a868SElliott Hughes {
469*d5c9a868SElliott Hughes return common_dos_loop(mp, arg, 0, mp->openflags);
470*d5c9a868SElliott Hughes }
471*d5c9a868SElliott Hughes
472*d5c9a868SElliott Hughes
dos_target_lookup(MainParam_t * mp,const char * arg)473*d5c9a868SElliott Hughes static int dos_target_lookup(MainParam_t *mp, const char *arg)
474*d5c9a868SElliott Hughes {
475*d5c9a868SElliott Hughes lookupState_t lookupState;
476*d5c9a868SElliott Hughes int ret;
477*d5c9a868SElliott Hughes int lookupflags;
478*d5c9a868SElliott Hughes
479*d5c9a868SElliott Hughes lookupState.nbDirs = 0;
480*d5c9a868SElliott Hughes lookupState.Dir = 0;
481*d5c9a868SElliott Hughes lookupState.nbContainers = 0;
482*d5c9a868SElliott Hughes lookupState.container = 0;
483*d5c9a868SElliott Hughes
484*d5c9a868SElliott Hughes lookupflags = mp->lookupflags;
485*d5c9a868SElliott Hughes mp->lookupflags = DO_OPEN | ACCEPT_DIR;
486*d5c9a868SElliott Hughes ret = common_dos_loop(mp, arg, &lookupState, O_RDWR);
487*d5c9a868SElliott Hughes mp->lookupflags = lookupflags;
488*d5c9a868SElliott Hughes if(ret & ERROR_ONE)
489*d5c9a868SElliott Hughes return ret;
490*d5c9a868SElliott Hughes
491*d5c9a868SElliott Hughes if(lookupState.nbDirs) {
492*d5c9a868SElliott Hughes mp->targetName = 0;
493*d5c9a868SElliott Hughes mp->targetDir = lookupState.Dir;
494*d5c9a868SElliott Hughes FREE(&lookupState.container); /* container no longer needed */
495*d5c9a868SElliott Hughes return ret;
496*d5c9a868SElliott Hughes }
497*d5c9a868SElliott Hughes
498*d5c9a868SElliott Hughes switch(lookupState.nbContainers) {
499*d5c9a868SElliott Hughes case 0:
500*d5c9a868SElliott Hughes /* no match */
501*d5c9a868SElliott Hughes fprintf(stderr,"%s: no match for target\n", arg);
502*d5c9a868SElliott Hughes return MISSED_ONE;
503*d5c9a868SElliott Hughes case 1:
504*d5c9a868SElliott Hughes mp->targetName = strdup(lookupState.filename);
505*d5c9a868SElliott Hughes mp->targetDir = lookupState.container;
506*d5c9a868SElliott Hughes return ret;
507*d5c9a868SElliott Hughes default:
508*d5c9a868SElliott Hughes /* too much */
509*d5c9a868SElliott Hughes fprintf(stderr, "Ambiguous %s\n", arg);
510*d5c9a868SElliott Hughes return ERROR_ONE;
511*d5c9a868SElliott Hughes }
512*d5c9a868SElliott Hughes }
513*d5c9a868SElliott Hughes
514*d5c9a868SElliott Hughes /*
515*d5c9a868SElliott Hughes * Is target a Unix directory
516*d5c9a868SElliott Hughes * -1 error occured
517*d5c9a868SElliott Hughes * 0 regular file
518*d5c9a868SElliott Hughes * 1 directory
519*d5c9a868SElliott Hughes */
unix_is_dir(const char * name)520*d5c9a868SElliott Hughes static int unix_is_dir(const char *name)
521*d5c9a868SElliott Hughes {
522*d5c9a868SElliott Hughes struct stat buf;
523*d5c9a868SElliott Hughes if(stat(name, &buf) < 0)
524*d5c9a868SElliott Hughes return -1;
525*d5c9a868SElliott Hughes else
526*d5c9a868SElliott Hughes return 1 && S_ISDIR(buf.st_mode);
527*d5c9a868SElliott Hughes }
528*d5c9a868SElliott Hughes
unix_target_lookup(MainParam_t * mp,const char * arg)529*d5c9a868SElliott Hughes static int unix_target_lookup(MainParam_t *mp, const char *arg)
530*d5c9a868SElliott Hughes {
531*d5c9a868SElliott Hughes char *ptr;
532*d5c9a868SElliott Hughes mp->unixTarget = strdup(arg);
533*d5c9a868SElliott Hughes /* try complete filename */
534*d5c9a868SElliott Hughes if(access(mp->unixTarget, F_OK) == 0) {
535*d5c9a868SElliott Hughes switch(unix_is_dir(mp->unixTarget)) {
536*d5c9a868SElliott Hughes case -1:
537*d5c9a868SElliott Hughes return ERROR_ONE;
538*d5c9a868SElliott Hughes case 0:
539*d5c9a868SElliott Hughes mp->targetName="";
540*d5c9a868SElliott Hughes break;
541*d5c9a868SElliott Hughes }
542*d5c9a868SElliott Hughes return GOT_ONE;
543*d5c9a868SElliott Hughes }
544*d5c9a868SElliott Hughes ptr = strrchr(mp->unixTarget, '/');
545*d5c9a868SElliott Hughes if(!ptr) {
546*d5c9a868SElliott Hughes mp->targetName = mp->unixTarget;
547*d5c9a868SElliott Hughes mp->unixTarget = strdup(".");
548*d5c9a868SElliott Hughes return GOT_ONE;
549*d5c9a868SElliott Hughes } else {
550*d5c9a868SElliott Hughes *ptr = '\0';
551*d5c9a868SElliott Hughes mp->targetName = ptr+1;
552*d5c9a868SElliott Hughes return GOT_ONE;
553*d5c9a868SElliott Hughes }
554*d5c9a868SElliott Hughes }
555*d5c9a868SElliott Hughes
target_lookup(MainParam_t * mp,const char * arg)556*d5c9a868SElliott Hughes int target_lookup(MainParam_t *mp, const char *arg)
557*d5c9a868SElliott Hughes {
558*d5c9a868SElliott Hughes if((mp->lookupflags & NO_UNIX) || (arg[0] && arg[1] == ':' ))
559*d5c9a868SElliott Hughes return dos_target_lookup(mp, arg);
560*d5c9a868SElliott Hughes else
561*d5c9a868SElliott Hughes return unix_target_lookup(mp, arg);
562*d5c9a868SElliott Hughes }
563*d5c9a868SElliott Hughes
main_loop(MainParam_t * mp,char ** argv,int argc)564*d5c9a868SElliott Hughes int main_loop(MainParam_t *mp, char **argv, int argc)
565*d5c9a868SElliott Hughes {
566*d5c9a868SElliott Hughes int i;
567*d5c9a868SElliott Hughes int ret, Bret;
568*d5c9a868SElliott Hughes
569*d5c9a868SElliott Hughes Bret = 0;
570*d5c9a868SElliott Hughes
571*d5c9a868SElliott Hughes if(argc != 1 && mp->targetName) {
572*d5c9a868SElliott Hughes fprintf(stderr,
573*d5c9a868SElliott Hughes "Several file names given, but last argument (%s) not a directory\n", mp->targetName);
574*d5c9a868SElliott Hughes FREE(&mp->targetDir);
575*d5c9a868SElliott Hughes return 1;
576*d5c9a868SElliott Hughes }
577*d5c9a868SElliott Hughes
578*d5c9a868SElliott Hughes for (i = 0; i < argc; i++) {
579*d5c9a868SElliott Hughes if ( got_signal )
580*d5c9a868SElliott Hughes break;
581*d5c9a868SElliott Hughes mp->originalArg = argv[i];
582*d5c9a868SElliott Hughes mp->basenameHasWildcard = strpbrk(_basename(mp->originalArg),
583*d5c9a868SElliott Hughes "*[?") != 0;
584*d5c9a868SElliott Hughes if (mp->unixcallback && (!argv[i][0]
585*d5c9a868SElliott Hughes #ifdef OS_mingw32msvc
586*d5c9a868SElliott Hughes /* On Windows, support only the command-line image drive. */
587*d5c9a868SElliott Hughes || argv[i][0] != ':'
588*d5c9a868SElliott Hughes #endif
589*d5c9a868SElliott Hughes || argv[i][1] != ':' ))
590*d5c9a868SElliott Hughes ret = unix_loop(0, mp, argv[i], 1);
591*d5c9a868SElliott Hughes else
592*d5c9a868SElliott Hughes ret = dos_loop(mp, argv[i]);
593*d5c9a868SElliott Hughes
594*d5c9a868SElliott Hughes if (! (ret & (GOT_ONE | ERROR_ONE)) ) {
595*d5c9a868SElliott Hughes /* one argument was unmatched */
596*d5c9a868SElliott Hughes fprintf(stderr, "%s: File \"%s\" not found\n",
597*d5c9a868SElliott Hughes progname, argv[i]);
598*d5c9a868SElliott Hughes ret |= ERROR_ONE;
599*d5c9a868SElliott Hughes }
600*d5c9a868SElliott Hughes Bret |= ret;
601*d5c9a868SElliott Hughes if(mp->fast_quit && (Bret & (MISSED_ONE | ERROR_ONE)))
602*d5c9a868SElliott Hughes break;
603*d5c9a868SElliott Hughes }
604*d5c9a868SElliott Hughes FREE(&mp->targetDir);
605*d5c9a868SElliott Hughes if(Bret & ERROR_ONE)
606*d5c9a868SElliott Hughes return 1;
607*d5c9a868SElliott Hughes if ((Bret & GOT_ONE) && ( Bret & MISSED_ONE))
608*d5c9a868SElliott Hughes return 2;
609*d5c9a868SElliott Hughes if (Bret & MISSED_ONE)
610*d5c9a868SElliott Hughes return 1;
611*d5c9a868SElliott Hughes return 0;
612*d5c9a868SElliott Hughes }
613*d5c9a868SElliott Hughes
dispatchToFile(direntry_t * entry,MainParam_t * mp)614*d5c9a868SElliott Hughes static int dispatchToFile(direntry_t *entry, MainParam_t *mp)
615*d5c9a868SElliott Hughes {
616*d5c9a868SElliott Hughes if(entry)
617*d5c9a868SElliott Hughes return mp->callback(entry, mp);
618*d5c9a868SElliott Hughes else
619*d5c9a868SElliott Hughes return mp->unixcallback(mp);
620*d5c9a868SElliott Hughes }
621*d5c9a868SElliott Hughes
622*d5c9a868SElliott Hughes
init_mp(MainParam_t * mp)623*d5c9a868SElliott Hughes void init_mp(MainParam_t *mp)
624*d5c9a868SElliott Hughes {
625*d5c9a868SElliott Hughes fix_mcwd(mp->mcwd);
626*d5c9a868SElliott Hughes mp->openflags = O_RDONLY;
627*d5c9a868SElliott Hughes mp->targetName = 0;
628*d5c9a868SElliott Hughes mp->targetDir = 0;
629*d5c9a868SElliott Hughes mp->unixTarget = 0;
630*d5c9a868SElliott Hughes mp->dirCallback = dispatchToFile;
631*d5c9a868SElliott Hughes mp->unixcallback = NULL;
632*d5c9a868SElliott Hughes mp->shortname.data = mp->longname.data = 0;
633*d5c9a868SElliott Hughes mp->shortname.len = mp->longname.len = 0;
634*d5c9a868SElliott Hughes mp->File = 0;
635*d5c9a868SElliott Hughes mp->fast_quit = 0;
636*d5c9a868SElliott Hughes }
637*d5c9a868SElliott Hughes
mpGetBasename(MainParam_t * mp)638*d5c9a868SElliott Hughes const char *mpGetBasename(MainParam_t *mp)
639*d5c9a868SElliott Hughes {
640*d5c9a868SElliott Hughes if(mp->direntry) {
641*d5c9a868SElliott Hughes wchar_to_native(mp->direntry->name, mp->targetBuffer,
642*d5c9a868SElliott Hughes MAX_VNAMELEN+1, sizeof(mp->targetBuffer));
643*d5c9a868SElliott Hughes return mp->targetBuffer;
644*d5c9a868SElliott Hughes } else
645*d5c9a868SElliott Hughes return _basename(mp->unixSourceName);
646*d5c9a868SElliott Hughes }
647*d5c9a868SElliott Hughes
mpPrintFilename(FILE * fp,MainParam_t * mp)648*d5c9a868SElliott Hughes void mpPrintFilename(FILE *fp, MainParam_t *mp)
649*d5c9a868SElliott Hughes {
650*d5c9a868SElliott Hughes if(mp->direntry)
651*d5c9a868SElliott Hughes fprintPwd(fp, mp->direntry, 0);
652*d5c9a868SElliott Hughes else
653*d5c9a868SElliott Hughes fprintf(fp,"%s",mp->originalArg);
654*d5c9a868SElliott Hughes }
655*d5c9a868SElliott Hughes
mpPickTargetName(MainParam_t * mp)656*d5c9a868SElliott Hughes const char *mpPickTargetName(MainParam_t *mp)
657*d5c9a868SElliott Hughes {
658*d5c9a868SElliott Hughes /* picks the target name: either the one explicitly given by the
659*d5c9a868SElliott Hughes * user, or the same as the source */
660*d5c9a868SElliott Hughes if(mp->targetName)
661*d5c9a868SElliott Hughes return mp->targetName;
662*d5c9a868SElliott Hughes else
663*d5c9a868SElliott Hughes return mpGetBasename(mp);
664*d5c9a868SElliott Hughes }
665*d5c9a868SElliott Hughes
mpBuildUnixFilename(MainParam_t * mp)666*d5c9a868SElliott Hughes char *mpBuildUnixFilename(MainParam_t *mp)
667*d5c9a868SElliott Hughes {
668*d5c9a868SElliott Hughes const char *target;
669*d5c9a868SElliott Hughes char *ret;
670*d5c9a868SElliott Hughes char *tmp;
671*d5c9a868SElliott Hughes
672*d5c9a868SElliott Hughes target = mpPickTargetName(mp);
673*d5c9a868SElliott Hughes ret = malloc(strlen(mp->unixTarget) + 2 + strlen(target));
674*d5c9a868SElliott Hughes if(!ret)
675*d5c9a868SElliott Hughes return 0;
676*d5c9a868SElliott Hughes strcpy(ret, mp->unixTarget);
677*d5c9a868SElliott Hughes if(*target) {
678*d5c9a868SElliott Hughes /* fix for 'mcopy -n x:file existingfile' -- H. Lermen 980816 */
679*d5c9a868SElliott Hughes if(!mp->targetName && !mp->targetDir && !unix_is_dir(ret))
680*d5c9a868SElliott Hughes return ret;
681*d5c9a868SElliott Hughes strcat(ret, "/");
682*d5c9a868SElliott Hughes if(!strcmp(target, ".")) {
683*d5c9a868SElliott Hughes target="DOT";
684*d5c9a868SElliott Hughes } else if(!strcmp(target, "..")) {
685*d5c9a868SElliott Hughes target="DOTDOT";
686*d5c9a868SElliott Hughes }
687*d5c9a868SElliott Hughes while( (tmp=strchr(target, '/')) ) {
688*d5c9a868SElliott Hughes strncat(ret, target, ptrdiff(tmp,target));
689*d5c9a868SElliott Hughes strcat(ret, "\\");
690*d5c9a868SElliott Hughes target=tmp+1;
691*d5c9a868SElliott Hughes }
692*d5c9a868SElliott Hughes strcat(ret, target);
693*d5c9a868SElliott Hughes }
694*d5c9a868SElliott Hughes return ret;
695*d5c9a868SElliott Hughes }
696