mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-10-31 08:21:36 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			353 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			353 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * (C) Copyright 2002
 | |
|  * Stäubli Faverges - <www.staubli.com>
 | |
|  * Pierre AUBERT  p.aubert@staubli.com
 | |
|  *
 | |
|  * See file CREDITS for list of people who contributed to this
 | |
|  * project.
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License as
 | |
|  * published by the Free Software Foundation; either version 2 of
 | |
|  * the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software
 | |
|  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 | |
|  * MA 02111-1307 USA
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <config.h>
 | |
| #include <linux/ctype.h>
 | |
| 
 | |
| #include "dos.h"
 | |
| #include "fdos.h"
 | |
| 
 | |
| static int dir_read (Fs_t *fs,
 | |
| 		     Slot_t *dir,
 | |
| 		     Directory_t *dirent,
 | |
| 		     int num,
 | |
| 		     struct vfat_state *v);
 | |
| 
 | |
| static int unicode_read (char *in, char *out, int num);
 | |
| static int match (const char *s, const char *p);
 | |
| static unsigned char sum_shortname (char *name);
 | |
| static int check_vfat (struct vfat_state *v, Directory_t *dir);
 | |
| static char *conv_name (char *name, char *ext, char Case, char *ans);
 | |
| 
 | |
| 
 | |
| /*-----------------------------------------------------------------------------
 | |
|  * clear_vfat --
 | |
|  *-----------------------------------------------------------------------------
 | |
|  */
 | |
| static void clear_vfat (struct vfat_state *v)
 | |
| {
 | |
|     v -> subentries = 0;
 | |
|     v -> status = 0;
 | |
| }
 | |
| 
 | |
| /*-----------------------------------------------------------------------------
 | |
|  * vfat_lookup --
 | |
|  *-----------------------------------------------------------------------------
 | |
|  */
 | |
| int vfat_lookup (Slot_t *dir,
 | |
| 		 Fs_t *fs,
 | |
| 		 Directory_t *dirent,
 | |
| 		 int *entry,
 | |
| 		 int *vfat_start,
 | |
| 		 char *filename,
 | |
| 		 int flags,
 | |
| 		 char *outname,
 | |
| 		 Slot_t *file)
 | |
| {
 | |
|     int found;
 | |
|     struct vfat_state vfat;
 | |
|     char newfile [VSE_NAMELEN];
 | |
|     int vfat_present = 0;
 | |
| 
 | |
|     if (*entry == -1) {
 | |
| 	return -1;
 | |
|     }
 | |
| 
 | |
|     found = 0;
 | |
|     clear_vfat (&vfat);
 | |
|     while (1) {
 | |
| 	if (dir_read (fs, dir, dirent, *entry, &vfat) < 0) {
 | |
| 	    if (vfat_start) {
 | |
| 		*vfat_start = *entry;
 | |
| 	    }
 | |
| 	    break;
 | |
| 	}
 | |
| 	(*entry)++;
 | |
| 
 | |
| 	/* Empty slot                                                        */
 | |
| 	if (dirent -> name[0] == '\0'){
 | |
| 	    if (vfat_start == 0) {
 | |
| 		break;
 | |
| 	    }
 | |
| 	    continue;
 | |
| 	}
 | |
| 
 | |
| 	if (dirent -> attr == ATTR_VSE) {
 | |
| 	    /* VSE entry, continue                                           */
 | |
| 	    continue;
 | |
| 	}
 | |
| 	if ( (dirent -> name [0] == DELMARK) ||
 | |
| 	     ((dirent -> attr & ATTR_DIRECTORY) != 0 &&
 | |
| 	      (flags & ACCEPT_DIR) == 0) ||
 | |
| 	     ((dirent -> attr & ATTR_VOLUME) != 0 &&
 | |
| 	      (flags & ACCEPT_LABEL) == 0) ||
 | |
| 	     (((dirent -> attr & (ATTR_DIRECTORY | ATTR_VOLUME)) == 0) &&
 | |
| 	      (flags & ACCEPT_PLAIN) == 0)) {
 | |
| 	    clear_vfat (&vfat);
 | |
| 	    continue;
 | |
| 	}
 | |
| 
 | |
| 	vfat_present = check_vfat (&vfat, dirent);
 | |
| 	if (vfat_start) {
 | |
| 	    *vfat_start = *entry - 1;
 | |
| 	    if (vfat_present) {
 | |
| 		*vfat_start -= vfat.subentries;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
| 	if (dirent -> attr & ATTR_VOLUME) {
 | |
| 	    strncpy (newfile, dirent -> name, 8);
 | |
| 	    newfile [8] = '\0';
 | |
| 	    strncat (newfile, dirent -> ext, 3);
 | |
| 	    newfile [11] = '\0';
 | |
| 	}
 | |
| 	else {
 | |
| 	    conv_name (dirent -> name, dirent -> ext, dirent -> Case, newfile);
 | |
| 	}
 | |
| 
 | |
| 	if (flags & MATCH_ANY) {
 | |
| 	    found = 1;
 | |
| 	    break;
 | |
| 	}
 | |
| 
 | |
| 	if ((vfat_present && match (vfat.name, filename)) ||
 | |
| 	    (match (newfile, filename))) {
 | |
| 	    found = 1;
 | |
| 	    break;
 | |
| 	}
 | |
| 	clear_vfat (&vfat);
 | |
|     }
 | |
| 
 | |
|     if (found) {
 | |
| 	if ((flags & DO_OPEN) && file) {
 | |
| 	    if (open_file (file, dirent) < 0) {
 | |
| 		return (-1);
 | |
| 	    }
 | |
| 	}
 | |
| 	if (outname) {
 | |
| 	    if (vfat_present) {
 | |
| 		strcpy (outname, vfat.name);
 | |
| 	    }
 | |
| 	    else {
 | |
| 		strcpy (outname, newfile);
 | |
| 	    }
 | |
| 	}
 | |
| 	return (0);                    /* File found                         */
 | |
|     } else {
 | |
| 	*entry = -1;
 | |
| 	return -1;                      /* File not found                    */
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*-----------------------------------------------------------------------------
 | |
|  * dir_read -- Read one directory entry
 | |
|  *-----------------------------------------------------------------------------
 | |
|  */
 | |
| static int dir_read (Fs_t *fs,
 | |
| 	      Slot_t *dir,
 | |
| 	      Directory_t *dirent,
 | |
| 	      int num,
 | |
| 	      struct vfat_state *v)
 | |
| {
 | |
| 
 | |
|     /* read the directory entry                                              */
 | |
|     if (read_file (fs,
 | |
| 		   dir,
 | |
| 		   (char *)dirent,
 | |
| 		   num * MDIR_SIZE,
 | |
| 		   MDIR_SIZE) != MDIR_SIZE) {
 | |
| 	return (-1);
 | |
|     }
 | |
| 
 | |
|     if (v && (dirent -> attr == ATTR_VSE)) {
 | |
| 	struct vfat_subentry *vse;
 | |
| 	unsigned char id, last_flag;
 | |
| 	char *c;
 | |
| 
 | |
| 	vse = (struct vfat_subentry *) dirent;
 | |
| 	id = vse -> id & VSE_MASK;
 | |
| 	last_flag = (vse -> id & VSE_LAST);
 | |
| 	if (id > MAX_VFAT_SUBENTRIES) {
 | |
| 	    /* Invalid VSE entry                                             */
 | |
| 	    return (-1);
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/* Decode VSE                                                        */
 | |
| 	if(v -> sum != vse -> sum) {
 | |
| 	    clear_vfat (v);
 | |
| 	    v -> sum = vse -> sum;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	v -> status |= 1 << (id - 1);
 | |
| 	if (last_flag) {
 | |
| 	    v -> subentries = id;
 | |
| 	}
 | |
| 
 | |
| 	c = &(v -> name [VSE_NAMELEN * (id - 1)]);
 | |
| 	c += unicode_read (vse->text1, c, VSE1SIZE);
 | |
| 	c += unicode_read (vse->text2, c, VSE2SIZE);
 | |
| 	c += unicode_read (vse->text3, c, VSE3SIZE);
 | |
| 
 | |
| 	if (last_flag) {
 | |
| 	    *c = '\0';	        /* Null terminate long name                  */
 | |
| 	}
 | |
| 
 | |
|     }
 | |
|     return (0);
 | |
| }
 | |
| 
 | |
| /*-----------------------------------------------------------------------------
 | |
|  * unicode_read --
 | |
|  *-----------------------------------------------------------------------------
 | |
|  */
 | |
| static int unicode_read (char *in, char *out, int num)
 | |
| {
 | |
|     int j;
 | |
| 
 | |
|     for (j = 0; j < num; ++j) {
 | |
| 	if (in [1])
 | |
| 	    *out = '_';
 | |
| 	else
 | |
| 	    *out = in [0];
 | |
| 	out ++;
 | |
| 	in += 2;
 | |
|     }
 | |
|     return num;
 | |
| }
 | |
| 
 | |
| /*-----------------------------------------------------------------------------
 | |
|  * match --
 | |
|  *-----------------------------------------------------------------------------
 | |
|  */
 | |
| static int match (const char *s, const char *p)
 | |
| {
 | |
| 
 | |
|     for (; *p != '\0'; ) {
 | |
| 	if (toupper (*s) != toupper (*p)) {
 | |
| 	    return (0);
 | |
| 	}
 | |
| 	p++;
 | |
| 	s++;
 | |
|     }
 | |
| 
 | |
|     if (*s != '\0') {
 | |
| 	return (0);
 | |
|     }
 | |
|     else {
 | |
| 	return (1);
 | |
|     }
 | |
| }
 | |
| /*-----------------------------------------------------------------------------
 | |
|  * sum_shortname --
 | |
|  *-----------------------------------------------------------------------------
 | |
|  */
 | |
| static unsigned char sum_shortname (char *name)
 | |
| {
 | |
|     unsigned char sum;
 | |
|     int j;
 | |
| 
 | |
|     for (j = sum = 0; j < 11; ++j) {
 | |
| 	sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) +
 | |
| 	    (name [j] ? name [j] : ' ');
 | |
|     }
 | |
|     return (sum);
 | |
| }
 | |
| /*-----------------------------------------------------------------------------
 | |
|  * check_vfat --
 | |
|  * Return 1 if long name is valid, 0 else
 | |
|  *-----------------------------------------------------------------------------
 | |
|  */
 | |
| static int check_vfat (struct vfat_state *v, Directory_t *dir)
 | |
| {
 | |
|     char name[12];
 | |
| 
 | |
|     if (v -> subentries == 0) {
 | |
| 	return 0;
 | |
|     }
 | |
| 
 | |
|     strncpy (name, dir -> name, 8);
 | |
|     strncpy (name + 8, dir -> ext, 3);
 | |
|     name [11] = '\0';
 | |
| 
 | |
|     if (v -> sum != sum_shortname (name)) {
 | |
| 	return 0;
 | |
|     }
 | |
| 
 | |
|     if( (v -> status & ((1 << v -> subentries) - 1)) !=
 | |
| 	(1 << v -> subentries) - 1) {
 | |
| 	return 0;
 | |
|     }
 | |
|     v->name [VSE_NAMELEN * v -> subentries] = 0;
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| /*-----------------------------------------------------------------------------
 | |
|  * conv_name --
 | |
|  *-----------------------------------------------------------------------------
 | |
|  */
 | |
| static char *conv_name (char *name, char *ext, char Case, char *ans)
 | |
| {
 | |
|     char tname [9], text [4];
 | |
|     int i;
 | |
| 
 | |
|     i = 0;
 | |
|     while (i < 8 && name [i] != ' ' && name [i] != '\0') {
 | |
| 	tname [i] = name [i];
 | |
| 	i++;
 | |
|     }
 | |
|     tname [i] = '\0';
 | |
| 
 | |
|     if (Case & BASECASE) {
 | |
| 	for (i = 0; i < 8 && tname [i]; i++) {
 | |
| 	    tname [i] = tolower (tname [i]);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     i = 0;
 | |
|     while (i < 3 && ext [i] != ' ' && ext [i] != '\0') {
 | |
| 	text [i] = ext [i];
 | |
| 	i++;
 | |
|     }
 | |
|     text [i] = '\0';
 | |
| 
 | |
|     if (Case & EXTCASE){
 | |
| 	for (i = 0; i < 3 && text [i]; i++) {
 | |
| 	    text [i] = tolower (text [i]);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     if (*text) {
 | |
| 	strcpy (ans, tname);
 | |
| 	strcat (ans, ".");
 | |
| 	strcat (ans, text);
 | |
|     }
 | |
|     else {
 | |
| 	strcpy(ans, tname);
 | |
|     }
 | |
|     return (ans);
 | |
| }
 |