xref: /aosp_15_r20/external/mtools/mk_direntry.c (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
1 /*  Copyright 1995-1998,2000-2003,2005,2007-2009 Alain Knaff.
2  *  This file is part of mtools.
3  *
4  *  Mtools is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Mtools is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * mk_direntry.c
18  * Make new directory entries, and handles name clashes
19  *
20  */
21 
22 /*
23  * This file is used by those commands that need to create new directory entries
24  */
25 
26 #include "sysincludes.h"
27 #include "msdos.h"
28 #include "mtools.h"
29 #include "vfat.h"
30 #include "nameclash.h"
31 #include "fs.h"
32 #include "stream.h"
33 #include "mainloop.h"
34 #include "file_name.h"
35 
36 /**
37  * Converts input to shortname
38  * @param un unix name (in Unix charset)
39  *
40  * @return 1 if name had to be mangled
41  */
convert_to_shortname(doscp_t * cp,ClashHandling_t * ch,const char * un,dos_name_t * dn)42 static __inline__ int convert_to_shortname(doscp_t *cp, ClashHandling_t *ch,
43 					   const char *un, dos_name_t *dn)
44 {
45 	int mangled;
46 
47 	/* Then do conversion to dn */
48 	ch->name_converter(cp, un, 0, &mangled, dn);
49 	dn->sentinel = '\0';
50 	if (dn->base[0] == '\xE5')
51 		dn->base[0] = '\x05';
52 	return mangled;
53 }
54 
chomp(char * line)55 static __inline__ void chomp(char *line)
56 {
57 	size_t l = strlen(line);
58 	while(l > 0 && (line[l-1] == '\n' || line[l-1] == '\r')) {
59 		line[--l] = '\0';
60 	}
61 }
62 
63 /**
64  * Asks for an alternative new name for a file, in case of a clash
65  */
ask_rename(doscp_t * cp,ClashHandling_t * ch,dos_name_t * shortname,char * longname,int isprimary)66 static __inline__ int ask_rename(doscp_t *cp, ClashHandling_t *ch,
67 				 dos_name_t *shortname,
68 				 char *longname,
69 				 int isprimary)
70 {
71 	int mangled;
72 
73 	/* TODO: Would be nice to suggest "autorenamed" version of name, press
74 	 * <Return> to get it.
75 	 */
76 #if 0
77 	fprintf(stderr,"Entering ask_rename, isprimary=%d.\n", isprimary);
78 #endif
79 
80 	if(!opentty(0))
81 		return 0;
82 
83 	mangled = 0;
84 	do {
85 		char tname[4*MAX_VNAMELEN+1];
86 		fprintf(stderr, "New %s name for \"%s\": ",
87 			isprimary ? "primary" : "secondary", longname);
88 		fflush(stderr);
89 		if (! fgets(tname, 4*MAX_VNAMELEN+1, opentty(0)))
90 			return 0;
91 		chomp(tname);
92 		if (isprimary)
93 			strcpy(longname, tname);
94 		else
95 			mangled = convert_to_shortname(cp,
96 						       ch, tname, shortname);
97 	} while (mangled & 1);
98 	return 1;
99 }
100 
101 /**
102  * This function determines the action to be taken in case there is a problem
103  * with target name (clash, illegal characters, or reserved)
104  * The decision either comes from the default (ch), or the user will be
105  * prompted if there is no default
106  */
ask_namematch(doscp_t * cp,dos_name_t * dosname,char * longname,int isprimary,ClashHandling_t * ch,int no_overwrite,int reason)107 static __inline__ clash_action ask_namematch(doscp_t *cp,
108 					     dos_name_t *dosname,
109 					     char *longname,
110 					     int isprimary,
111 					     ClashHandling_t *ch,
112 					     int no_overwrite,
113 					     int reason)
114 {
115 	/* User's answer letter (from keyboard). Only first letter is used,
116 	 * but we allocate space for 10 in order to account for extra garbage
117 	 * that user may enter
118 	 */
119 	char ans[10];
120 
121 	/**
122 	 * Return value: action to be taken
123 	 */
124 	clash_action a;
125 
126 	/**
127 	 * Should this decision be made permanent (do no longer ask same
128 	 * question)
129 	 */
130 	int perm;
131 
132 	/**
133 	 * Buffer for shortname
134 	 */
135 	char name_buffer[4*13];
136 
137 	/**
138 	 * Name to be printed
139 	 */
140 	char *name;
141 
142 #define EXISTS 0
143 #define RESERVED 1
144 #define ILLEGALS 2
145 
146 	static const char *reasons[]= {
147 		"already exists",
148 		"is reserved",
149 		"contains illegal character(s)"};
150 
151 	a = ch->action[isprimary];
152 
153 	if(a == NAMEMATCH_NONE && !opentty(1)) {
154 		/* no default, and no tty either . Skip the troublesome file */
155 		return NAMEMATCH_SKIP;
156 	}
157 
158 	if (!isprimary)
159 		name = unix_normalize(cp, name_buffer,
160 				      dosname, sizeof(*dosname));
161 	else
162 		name = longname;
163 
164 	perm = 0;
165 	while (a == NAMEMATCH_NONE) {
166 		fprintf(stderr, "%s file name \"%s\" %s.\n",
167 			isprimary ? "Long" : "Short", name, reasons[reason]);
168 		fprintf(stderr,
169 			"a)utorename A)utorename-all r)ename R)ename-all ");
170 		if(!no_overwrite)
171 			fprintf(stderr,"o)verwrite O)verwrite-all");
172 		fprintf(stderr,
173 			"\ns)kip S)kip-all q)uit (aArR");
174 		if(!no_overwrite)
175 			fprintf(stderr,"oO");
176 		fprintf(stderr,"sSq): ");
177 		fflush(stderr);
178 		fflush(opentty(1));
179 		if (mtools_raw_tty) {
180 			int rep;
181 			rep = fgetc(opentty(1));
182 			fputs("\n", stderr);
183 			if(rep == EOF)
184 				ans[0] = 'q';
185 			else
186 				ans[0] = (char) rep;
187 		} else {
188 			if(fgets(ans, 9, opentty(0)) == NULL)
189 				ans[0] = 'q';
190 		}
191 		perm = isupper((unsigned char)ans[0]);
192 		switch(tolower((unsigned char)ans[0])) {
193 			case 'a':
194 				a = NAMEMATCH_AUTORENAME;
195 				break;
196 			case 'r':
197 				if(isprimary)
198 					a = NAMEMATCH_PRENAME;
199 				else
200 					a = NAMEMATCH_RENAME;
201 				break;
202 			case 'o':
203 				if(no_overwrite)
204 					continue;
205 				a = NAMEMATCH_OVERWRITE;
206 				break;
207 			case 's':
208 				a = NAMEMATCH_SKIP;
209 				break;
210 			case 'q':
211 				perm = 0;
212 				a = NAMEMATCH_QUIT;
213 				break;
214 			default:
215 				perm = 0;
216 		}
217 	}
218 
219 	/* Keep track of this action in case this file collides again */
220 	ch->action[isprimary]  = a;
221 	if (perm)
222 		ch->namematch_default[isprimary] = a;
223 
224 	/* if we were asked to overwrite be careful. We can't set the action
225 	 * to overwrite, else we get won't get a chance to specify another
226 	 * action, should overwrite fail. Indeed, we'll be caught in an
227 	 * infinite loop because overwrite will fail the same way for the
228 	 * second time */
229 	if(a == NAMEMATCH_OVERWRITE)
230 		ch->action[isprimary] = NAMEMATCH_NONE;
231 	return a;
232 }
233 
234 /*
235  * Processes a name match
236  *  dosname short dosname (ignored if is_primary)
237  *
238  *
239  * Returns:
240  * 2 if file is to be overwritten
241  * 1 if file was renamed
242  * 0 if it was skipped
243  *
244  * If a short name is involved, handle conversion between the 11-character
245  * fixed-length record DOS name and a literal null-terminated name (e.g.
246  * "COMMAND  COM" (no null) <-> "COMMAND.COM" (null terminated)).
247  *
248  * Also, immediately copy the original name so that messages can use it.
249  */
process_namematch(doscp_t * cp,dos_name_t * dosname,char * longname,int isprimary,ClashHandling_t * ch,int no_overwrite,int reason)250 static __inline__ clash_action process_namematch(doscp_t *cp,
251 						 dos_name_t *dosname,
252 						 char *longname,
253 						 int isprimary,
254 						 ClashHandling_t *ch,
255 						 int no_overwrite,
256 						 int reason)
257 {
258 	clash_action action;
259 
260 #if 0
261 	fprintf(stderr,
262 		"process_namematch: name=%s, default_action=%d, ask=%d.\n",
263 		name, default_action, ch->ask);
264 #endif
265 
266 	action = ask_namematch(cp, dosname, longname,
267 			       isprimary, ch, no_overwrite, reason);
268 
269 	switch(action){
270 	case NAMEMATCH_QUIT:
271 		got_signal = 1;
272 		return NAMEMATCH_SKIP;
273 	case NAMEMATCH_SKIP:
274 		return NAMEMATCH_SKIP;
275 	case NAMEMATCH_RENAME:
276 	case NAMEMATCH_PRENAME:
277 		/* We need to rename the file now.  This means we must pass
278 		 * back through the loop, a) ensuring there isn't a potential
279 		 * new name collision, and b) finding a big enough VSE.
280 		 * Change the name, so that it won't collide again.
281 		 */
282 		ask_rename(cp, ch, dosname, longname, isprimary);
283 		return action;
284 	case NAMEMATCH_AUTORENAME:
285 		/* Very similar to NAMEMATCH_RENAME, except that we need to
286 		 * first generate the name.
287 		 * TODO: Remember previous name so we don't
288 		 * keep trying the same one.
289 		 */
290 		if (isprimary) {
291 			autorename_long(longname, 1);
292 			return NAMEMATCH_PRENAME;
293 		} else {
294 			autorename_short(dosname, 1);
295 			return NAMEMATCH_RENAME;
296 		}
297 	case NAMEMATCH_OVERWRITE:
298 		if(no_overwrite)
299 			return NAMEMATCH_SKIP;
300 		else
301 			return NAMEMATCH_OVERWRITE;
302 	case NAMEMATCH_NONE:
303 	case NAMEMATCH_ERROR:
304 	case NAMEMATCH_SUCCESS:
305 	case NAMEMATCH_GREW:
306 		return NAMEMATCH_NONE;
307 	}
308 	return action;
309 }
310 
contains_illegals(const char * string,const char * illegals,int len)311 static int contains_illegals(const char *string, const char *illegals,
312 			     int len)
313 {
314 	for(; *string && len--; string++)
315 		if((*string < ' ' && *string != '\005' && !(*string & 0x80)) ||
316 		   strchr(illegals, *string))
317 			return 1;
318 	return 0;
319 }
320 
is_reserved(char * ans,int islong)321 static int is_reserved(char *ans, int islong)
322 {
323 	unsigned int i;
324 	static const char *dev3[] = {"CON", "AUX", "PRN", "NUL", "   "};
325 	static const char *dev4[] = {"COM", "LPT" };
326 
327 	for (i = 0; i < sizeof(dev3)/sizeof(*dev3); i++)
328 		if (!strncasecmp(ans, dev3[i], 3) &&
329 		    ((islong && !ans[3]) ||
330 		     (!islong && !strncmp(ans+3,"     ",5))))
331 			return 1;
332 
333 	for (i = 0; i < sizeof(dev4)/sizeof(*dev4); i++)
334 		if (!strncasecmp(ans, dev4[i], 3) &&
335 		    (ans[3] >= '1' && ans[3] <= '4') &&
336 		    ((islong && !ans[4]) ||
337 		     (!islong && !strncmp(ans+4,"    ",4))))
338 			return 1;
339 
340 	return 0;
341 }
342 
get_slots(Stream_t * Dir,dos_name_t * dosname,char * longname,struct scan_state * ssp,ClashHandling_t * ch)343 static __inline__ clash_action get_slots(Stream_t *Dir,
344 					 dos_name_t *dosname,
345 					 char *longname,
346 					 struct scan_state *ssp,
347 					 ClashHandling_t *ch)
348 {
349 	int error;
350 	clash_action ret;
351 	int match_pos=0;
352 	direntry_t entry;
353 	int isprimary;
354 	int no_overwrite;
355 	int reason;
356 	int pessimisticShortRename;
357 	doscp_t *cp = GET_DOSCONVERT(Dir);
358 
359 	pessimisticShortRename = (ch->action[0] == NAMEMATCH_AUTORENAME);
360 
361 	entry.Dir = Dir;
362 	no_overwrite = 1;
363 	if((is_reserved(longname,1)) ||
364 	   longname[strspn(longname,". ")] == '\0'){
365 		reason = RESERVED;
366 		isprimary = 1;
367 	} else if(contains_illegals(longname,long_illegals,1024)) {
368 		reason = ILLEGALS;
369 		isprimary = 1;
370 	} else if(is_reserved(dosname->base,0)) {
371 		reason = RESERVED;
372 		ch->use_longname = 1;
373 		isprimary = 0;
374 	} else if(!ch->is_label &&
375 		  contains_illegals(dosname->base,short_illegals,11)) {
376 		reason = ILLEGALS;
377 		ch->use_longname = 1;
378 		isprimary = 0;
379 	} else {
380 		reason = EXISTS;
381 		switch (lookupForInsert(Dir,
382 					&entry,
383 					dosname, longname, ssp,
384 					ch->ignore_entry,
385 					ch->source_entry,
386 					pessimisticShortRename &&
387 					ch->use_longname,
388 					ch->use_longname)) {
389 			case -1:
390 				return NAMEMATCH_ERROR;
391 
392 			case 0:
393 				return NAMEMATCH_SKIP;
394 				/* Single-file error error or skip request */
395 
396 			case 5:
397 				return NAMEMATCH_GREW;
398 				/* Grew directory, try again */
399 
400 			case 6:
401 				return NAMEMATCH_SUCCESS; /* Success */
402 		}
403 		match_pos = -2;
404 		if (ssp->longmatch > -1) {
405 			/* Primary Long Name Match */
406 #ifdef debug
407 			fprintf(stderr,
408 				"Got longmatch=%d for name %s.\n",
409 				longmatch, longname);
410 #endif
411 			match_pos = ssp->longmatch;
412 			isprimary = 1;
413 		} else if ((ch->use_longname & 1) && (ssp->shortmatch != -1)) {
414 			/* Secondary Short Name Match */
415 #ifdef debug
416 			fprintf(stderr,
417 				"Got secondary short name match for name %s.\n",
418 				longname);
419 #endif
420 
421 			match_pos = ssp->shortmatch;
422 			isprimary = 0;
423 		} else if (ssp->shortmatch >= 0) {
424 			/* Primary Short Name Match */
425 #ifdef debug
426 			fprintf(stderr,
427 				"Got primary short name match for name %s.\n",
428 				longname);
429 #endif
430 			match_pos = ssp->shortmatch;
431 			isprimary = 1;
432 		} else
433 			return NAMEMATCH_RENAME;
434 
435 		if(match_pos > -1) {
436 			entry.entry = match_pos;
437 			dir_read(&entry, &error);
438 			if (error)
439 			    return NAMEMATCH_ERROR;
440 			/* if we can't overwrite, don't propose it */
441 			no_overwrite = (match_pos == ch->source || IS_DIR(&entry));
442 		}
443 	}
444 	ret = process_namematch(cp, dosname, longname,
445 				isprimary, ch, no_overwrite, reason);
446 
447 	if (ret == NAMEMATCH_OVERWRITE && match_pos > -1){
448 		if((entry.dir.attr & 0x5) &&
449 		   (ask_confirmation("file is read only, overwrite anyway (y/n) ? ")))
450 			return NAMEMATCH_RENAME;
451 		/* Free up the file to be overwritten */
452 		if(fatFreeWithDirentry(&entry))
453 			return NAMEMATCH_ERROR;
454 
455 #if 0
456 		if(isprimary &&
457 		   match_pos - ssp->match_free + 1 >= ssp->size_needed){
458 			/* reuse old entry and old short name for overwrite */
459 			ssp->free_start = match_pos - ssp->size_needed + 1;
460 			ssp->free_size = ssp->size_needed;
461 			ssp->slot = match_pos;
462 			ssp->got_slots = 1;
463 			strncpy(dosname, dir.name, 3);
464 			strncpy(dosname + 8, dir.ext, 3);
465 			return ret;
466 		} else
467 #endif
468 			{
469 			wipeEntry(&entry);
470 			return NAMEMATCH_RENAME;
471 		}
472 	}
473 
474 	return ret;
475 }
476 
477 
write_slots(Stream_t * Dir,dos_name_t * dosname,char * longname,struct scan_state * ssp,write_data_callback * cb,void * arg,int Case)478 static __inline__ int write_slots(Stream_t *Dir,
479 				  dos_name_t *dosname,
480 				  char *longname,
481 				  struct scan_state *ssp,
482 				  write_data_callback *cb,
483 				  void *arg,
484 				  int Case)
485 {
486 	direntry_t entry;
487 
488 	/* write the file */
489 	if (fat_error(Dir))
490 		return 0;
491 
492 	entry.Dir = Dir;
493 	entry.entry = ssp->slot;
494 	native_to_wchar(longname, entry.name, MAX_VNAMELEN, 0, 0);
495 	entry.name[MAX_VNAMELEN]='\0';
496 	entry.dir.Case = Case & (EXTCASE | BASECASE);
497 	if (cb(dosname, longname, arg, &entry) >= 0) {
498 		if ((ssp->size_needed > 1) &&
499 		    (ssp->free_end - ssp->free_start >= ssp->size_needed)) {
500 			ssp->slot = write_vfat(Dir, dosname, longname,
501 					       ssp->free_start, &entry);
502 		} else {
503 			ssp->size_needed = 1;
504 			write_vfat(Dir, dosname, 0,
505 				   ssp->free_start, &entry);
506 		}
507 		/* clear_vses(Dir, ssp->free_start + ssp->size_needed,
508 		   ssp->free_end); */
509 	} else
510 		return 0;
511 
512 	return 1;	/* Successfully wrote the file */
513 }
514 
stripspaces(char * name)515 static void stripspaces(char *name)
516 {
517 	char *p,*non_space;
518 
519 	non_space = name;
520 	for(p=name; *p; p++)
521 		if (*p != ' ')
522 			non_space = p;
523 	if(name[0])
524 		non_space[1] = '\0';
525 }
526 
527 
_mwrite_one(Stream_t * Dir,char * argname,char * shortname,write_data_callback * cb,void * arg,ClashHandling_t * ch)528 static int _mwrite_one(Stream_t *Dir,
529 		       char *argname,
530 		       char *shortname,
531 		       write_data_callback *cb,
532 		       void *arg,
533 		       ClashHandling_t *ch)
534 {
535 	char longname[VBUFSIZE];
536 	const char *dstname;
537 	dos_name_t dosname;
538 	int expanded;
539 	struct scan_state scan;
540 	clash_action ret;
541 	doscp_t *cp = GET_DOSCONVERT(Dir);
542 
543 	expanded = 0;
544 
545 	if(isSpecial(argname)) {
546 		fprintf(stderr, "Cannot create entry named . or ..\n");
547 		return -1;
548 	}
549 
550 	if(ch->name_converter == dos_name) {
551 		if(shortname)
552 			stripspaces(shortname);
553 		if(argname)
554 			stripspaces(argname);
555 	}
556 
557 	if(shortname){
558 		convert_to_shortname(cp, ch, shortname, &dosname);
559 		if(ch->use_longname & 1){
560 			/* short name mangled, treat it as a long name */
561 			argname = shortname;
562 			shortname = 0;
563 		}
564 	}
565 
566 	if (argname[0] && (argname[1] == ':')) {
567 		/* Skip drive letter */
568 		dstname = argname + 2;
569 	} else {
570 		dstname = argname;
571 	}
572 
573 	/* Copy original argument dstname to working value longname */
574 	strncpy(longname, dstname, VBUFSIZE-1);
575 
576 	if(shortname) {
577 		ch->use_longname =
578 			convert_to_shortname(cp, ch, shortname, &dosname);
579 		if(strcmp(shortname, longname))
580 			ch->use_longname |= 1;
581 	} else {
582 		ch->use_longname =
583 			convert_to_shortname(cp, ch, longname, &dosname);
584 	}
585 
586 	ch->action[0] = ch->namematch_default[0];
587 	ch->action[1] = ch->namematch_default[1];
588 
589 	while (1) {
590 		switch((ret=get_slots(Dir, &dosname, longname, &scan, ch))){
591 			case NAMEMATCH_ERROR:
592 				return -1;	/* Non-file-specific error,
593 						 * quit */
594 
595 			case NAMEMATCH_SKIP:
596 				return -1;	/* Skip file (user request or
597 						 * error) */
598 
599 			case NAMEMATCH_PRENAME:
600 				ch->use_longname =
601 					convert_to_shortname(cp, ch,
602 							     longname,
603 							     &dosname);
604 				continue;
605 			case NAMEMATCH_RENAME:
606 				continue;	/* Renamed file, loop again */
607 
608 			case NAMEMATCH_GREW:
609 				/* No collision, and not enough slots.
610 				 * Try to grow the directory
611 				 */
612 				if (expanded) {	/* Already tried this
613 						 * once, no good */
614 					fprintf(stderr,
615 						"%s: No directory slots\n",
616 						progname);
617 					return -1;
618 				}
619 				expanded = 1;
620 
621 				if (dir_grow(Dir, scan.max_entry))
622 					return -1;
623 				continue;
624 			case NAMEMATCH_OVERWRITE:
625 			case NAMEMATCH_SUCCESS:
626 				return write_slots(Dir, &dosname, longname,
627 						   &scan, cb, arg,
628 						   ch->use_longname);
629 			case NAMEMATCH_NONE:
630 			case NAMEMATCH_AUTORENAME:
631 			case NAMEMATCH_QUIT:
632 				fprintf(stderr,
633 					"Internal error: clash_action=%d\n",
634 					ret);
635 				return -1;
636 		}
637 
638 	}
639 }
640 
mwrite_one(Stream_t * Dir,const char * _argname,const char * _shortname,write_data_callback * cb,void * arg,ClashHandling_t * ch)641 int mwrite_one(Stream_t *Dir,
642 	       const char *_argname,
643 	       const char *_shortname,
644 	       write_data_callback *cb,
645 	       void *arg,
646 	       ClashHandling_t *ch)
647 {
648 	char *argname;
649 	char *shortname;
650 	int ret;
651 
652 	if(_argname)
653 		argname = strdup(_argname);
654 	else
655 		argname = 0;
656 	if(_shortname)
657 		shortname = strdup(_shortname);
658 	else
659 		shortname = 0;
660 	ret = _mwrite_one(Dir, argname, shortname, cb, arg, ch);
661 	if(argname)
662 		free(argname);
663 	if(shortname)
664 		free(shortname);
665 	return ret;
666 }
667 
init_clash_handling(ClashHandling_t * ch)668 void init_clash_handling(ClashHandling_t *ch)
669 {
670 	ch->ignore_entry = -1;
671 	ch->source_entry = -2;
672 	ch->nowarn = 0;	/*Don't ask, just do default action if name collision */
673 	ch->namematch_default[0] = NAMEMATCH_AUTORENAME;
674 	ch->namematch_default[1] = NAMEMATCH_NONE;
675 	ch->name_converter = dos_name; /* changed by mlabel */
676 	ch->source = -2;
677 	ch->is_label = 0;
678 }
679 
handle_clash_options(ClashHandling_t * ch,char c)680 int handle_clash_options(ClashHandling_t *ch, char c)
681 {
682 	int isprimary;
683 	if(isupper(c))
684 		isprimary = 0;
685 	else
686 		isprimary = 1;
687 	c = ch_tolower(c);
688 	switch(c) {
689 		case 'o':
690 			/* Overwrite if primary name matches */
691 			ch->namematch_default[isprimary] = NAMEMATCH_OVERWRITE;
692 			return 0;
693 		case 'r':
694 				/* Rename primary name interactively */
695 			ch->namematch_default[isprimary] = NAMEMATCH_RENAME;
696 			return 0;
697 		case 's':
698 			/* Skip file if primary name collides */
699 			ch->namematch_default[isprimary] = NAMEMATCH_SKIP;
700 			return 0;
701 		case 'm':
702 			ch->namematch_default[isprimary] = NAMEMATCH_NONE;
703 			return 0;
704 		case 'a':
705 			ch->namematch_default[isprimary] = NAMEMATCH_AUTORENAME;
706 			return 0;
707 		default:
708 			return -1;
709 	}
710 }
711 
dosnameToDirentry(const struct dos_name_t * dn,struct directory * dir)712 void dosnameToDirentry(const struct dos_name_t *dn, struct directory *dir) {
713 	strncpy(dir->name, dn->base, 8);
714 	strncpy(dir->ext, dn->ext, 3);
715 }
716