source: trunk/minix/commands/i386/mtools-3.9.7/mainloop.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 11.8 KB
Line 
1/*
2 * mainloop.c
3 * Iterating over all the command line parameters, and matching patterns
4 * where needed
5 */
6
7#include "sysincludes.h"
8#include "msdos.h"
9#include "mtools.h"
10#include "vfat.h"
11#include "fs.h"
12#include "mainloop.h"
13#include "plain_io.h"
14#include "file.h"
15
16
17int unix_dir_loop(Stream_t *Stream, MainParam_t *mp);
18int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg,
19 int follow_dir_link);
20
21static int _unix_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
22{
23 unix_dir_loop(Dir, mp);
24 return GOT_ONE;
25}
26
27int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, int follow_dir_link)
28{
29 int ret;
30 int isdir;
31
32 mp->File = NULL;
33 mp->direntry = NULL;
34 mp->unixSourceName = arg;
35 /* mp->dir.attr = ATTR_ARCHIVE;*/
36 mp->loop = _unix_loop;
37 if((mp->lookupflags & DO_OPEN)){
38 mp->File = SimpleFileOpen(0, 0, arg, O_RDONLY, 0, 0, 0, 0);
39 if(!mp->File){
40 perror(arg);
41#if 0
42 tmp = _basename(arg);
43 strncpy(mp->filename, tmp, VBUFSIZE);
44 mp->filename[VBUFSIZE-1] = '\0';
45#endif
46 return ERROR_ONE;
47 }
48 GET_DATA(mp->File, 0, 0, &isdir, 0);
49 if(isdir) {
50 struct stat buf;
51
52 FREE(&mp->File);
53#ifdef S_ISLNK
54 if(!follow_dir_link &&
55 lstat(arg, &buf) == 0 &&
56 S_ISLNK(buf.st_mode)) {
57 /* skip links to directories in order to avoid
58 * infinite loops */
59 fprintf(stderr,
60 "skipping directory symlink %s\n",
61 arg);
62 return 0;
63 }
64#endif
65 if(! (mp->lookupflags & ACCEPT_DIR))
66 return 0;
67 mp->File = OpenDir(Stream, arg);
68 }
69 }
70
71 if(isdir)
72 ret = mp->dirCallback(0, mp);
73 else
74 ret = mp->unixcallback(mp);
75 FREE(&mp->File);
76 return ret;
77}
78
79
80int isSpecial(const char *name)
81{
82 if(name[0] == '\0')
83 return 1;
84 if(!strcmp(name,"."))
85 return 1;
86 if(!strcmp(name,".."))
87 return 1;
88 return 0;
89}
90
91
92static int checkForDot(int lookupflags, const char *name)
93{
94 return (lookupflags & NO_DOTS) && isSpecial(name);
95}
96
97
98typedef struct lookupState_t {
99 Stream_t *container;
100 int nbContainers;
101 Stream_t *Dir;
102 int nbDirs;
103 const char *filename;
104} lookupState_t;
105
106static int isUniqueTarget(const char *name)
107{
108 return name && strcmp(name, "-");
109}
110
111static int handle_leaf(direntry_t *direntry, MainParam_t *mp,
112 lookupState_t *lookupState)
113{
114 Stream_t *MyFile=0;
115 int ret;
116
117 if(got_signal)
118 return ERROR_ONE;
119 if(lookupState) {
120 /* we are looking for a "target" file */
121 switch(lookupState->nbDirs) {
122 case 0: /* no directory yet, open it */
123 lookupState->Dir = OpenFileByDirentry(direntry);
124 lookupState->nbDirs++;
125 /* dump the container, we have
126 * better now */
127 FREE(&lookupState->container);
128 return 0;
129 case 1: /* we have already a directory */
130 FREE(&lookupState->Dir);
131 fprintf(stderr,"Ambigous\n");
132 return STOP_NOW | ERROR_ONE;
133 default:
134 return STOP_NOW | ERROR_ONE;
135 }
136 }
137
138 mp->direntry = direntry;
139 if(IS_DIR(direntry)) {
140 if(mp->lookupflags & (DO_OPEN | DO_OPEN_DIRS))
141 MyFile = mp->File = OpenFileByDirentry(direntry);
142 ret = mp->dirCallback(direntry, mp);
143 } else {
144 if(mp->lookupflags & DO_OPEN)
145 MyFile = mp->File = OpenFileByDirentry(direntry);
146 ret = mp->callback(direntry, mp);
147 }
148 FREE(&MyFile);
149 if(isUniqueTarget(mp->targetName))
150 ret |= STOP_NOW;
151 return ret;
152}
153
154static int _dos_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
155{
156 Stream_t *MyFile=0;
157 direntry_t entry;
158 int ret;
159 int r;
160
161 ret = 0;
162 r=0;
163 initializeDirentry(&entry, Dir);
164 while(!got_signal &&
165 (r=vfat_lookup(&entry, filename, -1,
166 mp->lookupflags, mp->shortname,
167 mp->longname)) == 0 ){
168 mp->File = NULL;
169 if(!checkForDot(mp->lookupflags,entry.name)) {
170 MyFile = 0;
171 if((mp->lookupflags & DO_OPEN) ||
172 (IS_DIR(&entry) &&
173 (mp->lookupflags & DO_OPEN_DIRS))) {
174 MyFile = mp->File = OpenFileByDirentry(&entry);
175 }
176 if(got_signal)
177 break;
178 mp->direntry = &entry;
179 if(IS_DIR(&entry))
180 ret |= mp->dirCallback(&entry,mp);
181 else
182 ret |= mp->callback(&entry, mp);
183 FREE(&MyFile);
184 }
185 if (fat_error(Dir))
186 ret |= ERROR_ONE;
187 if(mp->fast_quit && (ret & ERROR_ONE))
188 break;
189 }
190 if (r == -2)
191 return ERROR_ONE;
192 if(got_signal)
193 ret |= ERROR_ONE;
194 return ret;
195}
196
197static int recurs_dos_loop(MainParam_t *mp, const char *filename0,
198 const char *filename1,
199 lookupState_t *lookupState)
200{
201 /* Dir is de-allocated by the same entity which allocated it */
202 const char *ptr;
203 direntry_t entry;
204 int length;
205 int lookupflags;
206 int ret;
207 int have_one;
208 int doing_mcwd;
209 int r;
210
211 while(1) {
212 /* strip dots and // */
213 if(!strncmp(filename0,"./", 2)) {
214 filename0 += 2;
215 continue;
216 }
217 if(!strcmp(filename0,".") && filename1) {
218 filename0 ++;
219 continue;
220 }
221 if(filename0[0] == '/') {
222 filename0++;
223 continue;
224 }
225 if(!filename0[0]) {
226 if(!filename1)
227 break;
228 filename0 = filename1;
229 filename1 = 0;
230 continue;
231 }
232 break;
233 }
234
235 if(!strncmp(filename0,"../", 3) ||
236 (!strcmp(filename0, "..") && filename1)) {
237 /* up one level */
238 mp->File = getDirentry(mp->File)->Dir;
239 return recurs_dos_loop(mp, filename0+2, filename1, lookupState);
240 }
241
242 doing_mcwd = !!filename1;
243
244 ptr = strchr(filename0, '/');
245 if(!ptr) {
246 length = strlen(filename0);
247 ptr = filename1;
248 filename1 = 0;
249 } else {
250 length = ptr - filename0;
251 ptr++;
252 }
253 if(!ptr) {
254 if(mp->lookupflags & OPEN_PARENT) {
255 mp->targetName = filename0;
256 ret = handle_leaf(getDirentry(mp->File), mp,
257 lookupState);
258 mp->targetName = 0;
259 return ret;
260 }
261
262 if(!strcmp(filename0, ".") || !filename0[0]) {
263 return handle_leaf(getDirentry(mp->File),
264 mp, lookupState);
265 }
266
267 if(!strcmp(filename0, "..")) {
268 return handle_leaf(getParent(getDirentry(mp->File)), mp,
269 lookupState);
270 }
271
272 lookupflags = mp->lookupflags;
273
274 if(lookupState) {
275 lookupState->filename = filename0;
276 if(lookupState->nbContainers + lookupState->nbDirs > 0){
277 /* we have already one target, don't bother
278 * with this one. */
279 FREE(&lookupState->container);
280 } else {
281 /* no match yet. Remember this container for
282 * later use */
283 lookupState->container = COPY(mp->File);
284 }
285 lookupState->nbContainers++;
286 }
287 } else
288 lookupflags = ACCEPT_DIR | DO_OPEN | NO_DOTS;
289
290 ret = 0;
291 r = 0;
292 have_one = 0;
293 initializeDirentry(&entry, mp->File);
294 while(!(ret & STOP_NOW) &&
295 !got_signal &&
296 (r=vfat_lookup(&entry, filename0, length,
297 lookupflags | NO_MSG,
298 mp->shortname, mp->longname)) == 0 ){
299 if(checkForDot(lookupflags, entry.name))
300 /* while following the path, ignore the
301 * special entries if they were not
302 * explicitly given */
303 continue;
304 have_one = 1;
305 if(ptr) {
306 Stream_t *SubDir;
307 SubDir = mp->File = OpenFileByDirentry(&entry);
308 ret |= recurs_dos_loop(mp, ptr, filename1, lookupState);
309 FREE(&SubDir);
310 } else {
311 ret |= handle_leaf(&entry, mp, lookupState);
312 if(isUniqueTarget(mp->targetName))
313 return ret | STOP_NOW;
314 }
315 if(doing_mcwd)
316 break;
317 }
318 if (r == -2)
319 return ERROR_ONE;
320 if(got_signal)
321 return ret | ERROR_ONE;
322 if(doing_mcwd & !have_one)
323 return NO_CWD;
324 return ret;
325}
326
327static int common_dos_loop(MainParam_t *mp, const char *pathname,
328 lookupState_t *lookupState, int open_mode)
329
330{
331 Stream_t *RootDir;
332 char *cwd;
333 char *drive;
334 char *rest;
335
336 int ret;
337 mp->loop = _dos_loop;
338
339 drive='\0';
340 cwd = "";
341 if((rest = skip_drive(pathname)) > pathname) {
342 drive = get_drive(pathname, NULL);
343 if (strncmp(pathname, mp->mcwd, rest - pathname) == 0)
344 cwd = skip_drive(mp->mcwd);
345 pathname = rest;
346 } else {
347 drive = get_drive(mp->mcwd, NULL);
348 cwd = skip_drive(mp->mcwd);
349 }
350
351 if(*pathname=='/') /* absolute path name */
352 cwd = "";
353
354 RootDir = mp->File = open_root_dir(drive, open_mode);
355 if(!mp->File)
356 return ERROR_ONE;
357
358 ret = recurs_dos_loop(mp, cwd, pathname, lookupState);
359 if(ret & NO_CWD) {
360 /* no CWD */
361 *mp->mcwd = '\0';
362 unlink_mcwd();
363 ret = recurs_dos_loop(mp, "", pathname, lookupState);
364 }
365 FREE(&RootDir);
366 return ret;
367}
368
369static int dos_loop(MainParam_t *mp, const char *arg)
370{
371 return common_dos_loop(mp, arg, 0, mp->openflags);
372}
373
374
375static int dos_target_lookup(MainParam_t *mp, const char *arg)
376{
377 lookupState_t lookupState;
378 int ret;
379 int lookupflags;
380
381 lookupState.nbDirs = 0;
382 lookupState.Dir = 0;
383 lookupState.nbContainers = 0;
384 lookupState.container = 0;
385
386 lookupflags = mp->lookupflags;
387 mp->lookupflags = DO_OPEN | ACCEPT_DIR;
388 ret = common_dos_loop(mp, arg, &lookupState, O_RDWR);
389 mp->lookupflags = lookupflags;
390 if(ret & ERROR_ONE)
391 return ret;
392
393 if(lookupState.nbDirs) {
394 mp->targetName = 0;
395 mp->targetDir = lookupState.Dir;
396 FREE(&lookupState.container); /* container no longer needed */
397 return ret;
398 }
399
400 switch(lookupState.nbContainers) {
401 case 0:
402 /* no match */
403 fprintf(stderr,"%s: no match for target\n", arg);
404 return MISSED_ONE;
405 case 1:
406 mp->targetName = strdup(lookupState.filename);
407 mp->targetDir = lookupState.container;
408 return ret;
409 default:
410 /* too much */
411 fprintf(stderr, "Ambigous %s\n", arg);
412 return ERROR_ONE;
413 }
414}
415
416int unix_target_lookup(MainParam_t *mp, const char *arg)
417{
418 char *ptr;
419 mp->unixTarget = strdup(arg);
420 /* try complete filename */
421 if(access(mp->unixTarget, F_OK) == 0)
422 return GOT_ONE;
423 ptr = strrchr(mp->unixTarget, '/');
424 if(!ptr) {
425 mp->targetName = mp->unixTarget;
426 mp->unixTarget = strdup(".");
427 return GOT_ONE;
428 } else {
429 *ptr = '\0';
430 mp->targetName = ptr+1;
431 return GOT_ONE;
432 }
433}
434
435int target_lookup(MainParam_t *mp, const char *arg)
436{
437 if((mp->lookupflags & NO_UNIX) || skip_drive(arg) > arg)
438 return dos_target_lookup(mp, arg);
439 else
440 return unix_target_lookup(mp, arg);
441}
442
443int main_loop(MainParam_t *mp, char **argv, int argc)
444{
445 int i;
446 int ret, Bret;
447
448 Bret = 0;
449
450 if(argc != 1 && mp->targetName) {
451 fprintf(stderr,
452 "Several file names given, but last argument (%s) not a directory\n", mp->targetName);
453 }
454
455 for (i = 0; i < argc; i++) {
456 if ( got_signal )
457 break;
458 mp->originalArg = argv[i];
459 mp->basenameHasWildcard = strpbrk(_basename(mp->originalArg),
460 "*[?") != 0;
461 if (mp->unixcallback && skip_drive(argv[i]) == argv[i])
462 ret = unix_loop(0, mp, argv[i], 1);
463 else
464 ret = dos_loop(mp, argv[i]);
465
466 if (! (ret & (GOT_ONE | ERROR_ONE)) ) {
467 /* one argument was unmatched */
468 fprintf(stderr, "%s: File \"%s\" not found\n",
469 progname, argv[i]);
470 ret |= ERROR_ONE;
471 }
472 Bret |= ret;
473 if(mp->fast_quit && (Bret & (MISSED_ONE | ERROR_ONE)))
474 break;
475 }
476 FREE(&mp->targetDir);
477 if(Bret & ERROR_ONE)
478 return 1;
479 if ((Bret & GOT_ONE) && ( Bret & MISSED_ONE))
480 return 2;
481 if (Bret & MISSED_ONE)
482 return 1;
483 return 0;
484}
485
486static int dispatchToFile(direntry_t *entry, MainParam_t *mp)
487{
488 if(entry)
489 return mp->callback(entry, mp);
490 else
491 return mp->unixcallback(mp);
492}
493
494
495void init_mp(MainParam_t *mp)
496{
497 fix_mcwd(mp->mcwd);
498 mp->openflags = 0;
499 mp->targetName = 0;
500 mp->targetDir = 0;
501 mp->unixTarget = 0;
502 mp->dirCallback = dispatchToFile;
503 mp->unixcallback = NULL;
504 mp->shortname = mp->longname = 0;
505 mp->File = 0;
506 mp->fast_quit = 0;
507}
508
509const char *mpGetBasename(MainParam_t *mp)
510{
511 if(mp->direntry)
512 return mp->direntry->name;
513 else
514 return _basename(mp->unixSourceName);
515}
516
517void mpPrintFilename(FILE *fp, MainParam_t *mp)
518{
519 if(mp->direntry)
520 fprintPwd(fp, mp->direntry, 0);
521 else
522 fprintf(fp,"%s",mp->originalArg);
523}
524
525const char *mpPickTargetName(MainParam_t *mp)
526{
527 /* picks the target name: either the one explicitly given by the
528 * user, or the same as the source */
529 if(mp->targetName)
530 return mp->targetName;
531 else
532 return mpGetBasename(mp);
533}
534
535char *mpBuildUnixFilename(MainParam_t *mp)
536{
537 const char *target;
538 char *ret;
539
540 target = mpPickTargetName(mp);
541 ret = malloc(strlen(mp->unixTarget) + 2 + strlen(target));
542 if(!ret)
543 return 0;
544 strcpy(ret, mp->unixTarget);
545 if(*target) {
546#if 1 /* fix for 'mcopy -n x:file existingfile' -- H. Lermen 980816 */
547 if(!mp->targetName && !mp->targetDir) {
548 struct stat buf;
549 if (!stat(ret, &buf) && !S_ISDIR(buf.st_mode))
550 return ret;
551 }
552#endif
553 strcat(ret, "/");
554 strcat(ret, target);
555 }
556 return ret;
557}
Note: See TracBrowser for help on using the repository browser.