/* *============================================================================= * File: dos_util.c * Purpose: This file constitutes the "VFat" layer, which * consists of remnants from "dos_utils.c" and a * whole bunch of functions that are required to * support Windows 95 style long file names. *============================================================================= */ #include #include #include #include #include #include #include #include "dos_fs.h" extern int debug; /* Debug flag */ struct unicode_value { unsigned char uni1; unsigned char uni2; }; struct unicode_value a2uni[]; /* Ascii to Unicode conversion table */ unsigned char *uni2asc_pg[]; /* Unicode to Ascii conversion table */ struct unicode_value a2uni[256] = { /* 0x00 */ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00}, {0x08, 0x00}, {0x09, 0x00}, {0x0A, 0x00}, {0x0B, 0x00}, {0x0C, 0x00}, {0x0D, 0x00}, {0x0E, 0x00}, {0x0F, 0x00}, /* 0x10 */ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00}, {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00}, {0x18, 0x00}, {0x19, 0x00}, {0x1A, 0x00}, {0x1B, 0x00}, {0x1C, 0x00}, {0x1D, 0x00}, {0x1E, 0x00}, {0x1F, 0x00}, /* 0x20 */ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00}, {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00}, {0x29, 0x00}, {0x2A, 0x00}, {0x2B, 0x00}, {0x2C, 0x00}, {0x2D, 0x00}, {0x2E, 0x00}, {0x2F, 0x00}, /* 0x30 */ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00}, {0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x00}, {0x3C, 0x00}, {0x3D, 0x00}, {0x3E, 0x00}, {0x3F, 0x00}, /* 0x40 */ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00}, {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00}, {0x48, 0x00}, {0x49, 0x00}, {0x4A, 0x00}, {0x4B, 0x00}, {0x4C, 0x00}, {0x4D, 0x00}, {0x4E, 0x00}, {0x4F, 0x00}, /* 0x50 */ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00}, {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00}, {0x58, 0x00}, {0x59, 0x00}, {0x5A, 0x00}, {0x5B, 0x00}, {0x5C, 0x00}, {0x5D, 0x00}, {0x5E, 0x00}, {0x5F, 0x00}, /* 0x60 */ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00}, {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00}, {0x68, 0x00}, {0x69, 0x00}, {0x6A, 0x00}, {0x6B, 0x00}, {0x6C, 0x00}, {0x6D, 0x00}, {0x6E, 0x00}, {0x6F, 0x00}, /* 0x70 */ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00}, {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00}, {0x78, 0x00}, {0x79, 0x00}, {0x7A, 0x00}, {0x7B, 0x00}, {0x7C, 0x00}, {0x7D, 0x00}, {0x7E, 0x00}, {0x7F, 0x00}, /* 0x80 */ {0xC7, 0x00}, {0xFC, 0x00}, {0xE9, 0x00}, {0xE2, 0x00}, {0xE4, 0x00}, {0xE0, 0x00}, {0xE5, 0x00}, {0xE7, 0x00}, {0xEA, 0x00}, {0xEB, 0x00}, {0xE8, 0x00}, {0xEF, 0x00}, {0xEE, 0x00}, {0xEC, 0x00}, {0xC4, 0x00}, {0xC5, 0x00}, /* 0x90 */ {0xC9, 0x00}, {0xE6, 0x00}, {0xC6, 0x00}, {0xF4, 0x00}, {0xF6, 0x00}, {0xF2, 0x00}, {0xFB, 0x00}, {0xF9, 0x00}, {0xFF, 0x00}, {0xD6, 0x00}, {0xDC, 0x00}, {0xF8, 0x00}, {0xA3, 0x00}, {0xD8, 0x00}, {0xD7, 0x00}, {0x92, 0x00}, /* 0xA0 */ {0xE1, 0x00}, {0xE0, 0x00}, {0xF3, 0x00}, {0xFA, 0x00}, {0xF1, 0x00}, {0xD1, 0x00}, {0xAA, 0x00}, {0xBA, 0x00}, {0xBF, 0x00}, {0xAE, 0x00}, {0xAC, 0x00}, {0xBD, 0x00}, {0xBC, 0x00}, {0xA1, 0x00}, {0xAB, 0x00}, {0xBB, 0x00}, /* 0xB0 */ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25}, {0x24, 0x25}, {0xC1, 0x00}, {0xC2, 0x00}, {0xC0, 0x00}, {0xA9, 0x00}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25}, {0x5D, 0x25}, {0xA2, 0x00}, {0xA5, 0x00}, {0x10, 0x25}, /* 0xC0 */ {0x14, 0x25}, {0x34, 0x25}, {0x2C, 0x25}, {0x1C, 0x25}, {0x00, 0x25}, {0x3C, 0x25}, {0xE3, 0x00}, {0xC3, 0x00}, {0x5A, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25}, {0x60, 0x25}, {0x50, 0x25}, {0x6C, 0x25}, {0xA4, 0x00}, /* 0xD0 */ {0xF0, 0x00}, {0xD0, 0x00}, {0xCA, 0x00}, {0xCB, 0x00}, {0xC8, 0x00}, {0x31, 0x01}, {0xCD, 0x00}, {0xCE, 0x00}, {0xCF, 0x00}, {0x18, 0x25}, {0x0C, 0x25}, {0x88, 0x25}, {0x84, 0x25}, {0xA6, 0x00}, {0xCC, 0x00}, {0x80, 0x25}, /* 0xE0 */ {0xD3, 0x00}, {0xDF, 0x00}, {0xD4, 0x00}, {0xD2, 0x00}, {0xF5, 0x00}, {0xD5, 0x00}, {0xB5, 0x00}, {0xFE, 0x00}, {0xDE, 0x00}, {0xDA, 0x00}, {0xDB, 0x00}, {0xD9, 0x00}, {0xFD, 0x00}, {0xDD, 0x00}, {0xAF, 0x00}, {0xB4, 0x00}, /* 0xF0 */ {0xAD, 0x00}, {0xB1, 0x00}, {0x17, 0x20}, {0xBE, 0x00}, {0xB6, 0x00}, {0xA7, 0x00}, {0xF7, 0x00}, {0xB8, 0x00}, {0xB0, 0x00}, {0xA8, 0x00}, {0xB7, 0x00}, {0xB9, 0x00}, {0xB3, 0x00}, {0xB2, 0x00}, {0xA0, 0x25}, {0xA0, 0x00} }; unsigned char page00[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 0x08-0x0F */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* 0x18-0x1F */ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, /* 0x28-0x2F */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, /* 0x38-0x3F */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* 0x48-0x4F */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, /* 0x58-0x5F */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, /* 0x68-0x6F */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, /* 0x78-0x7F */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8F */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, /* 0x98-0x9F */ 0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, /* 0xA0-0xA7 */ 0xF9, 0xB8, 0x00, 0xAE, 0xAA, 0xF0, 0x00, 0xEE, /* 0xA8-0xAF */ 0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, /* 0xB0-0xB7 */ 0xF7, 0xFB, 0x00, 0xAF, 0xAC, 0xAB, 0xF3, 0x00, /* 0xB8-0xBF */ 0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, /* 0xC0-0xC7 */ 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8, /* 0xC8-0xCF */ 0x00, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, /* 0xD0-0xD7 */ 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1, /* 0xD8-0xDF */ 0xA1, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, /* 0xE0-0xE7 */ 0x8A, 0x82, 0x88, 0x89, 0x8D, 0x00, 0x8C, 0x8B, /* 0xE8-0xEF */ 0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, /* 0xF0-0xF7 */ 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98 /* 0xF8-0xFF */ }; unsigned char page25[256] = { 0xC4, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ 0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x00, 0x00, /* 0x08-0x0F */ 0xBF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ 0xD9, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, /* 0x18-0x1F */ 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ 0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, /* 0x28-0x2F */ 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, /* 0x38-0x3F */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4F */ 0xCD, 0xBA, 0x00, 0x00, 0xC9, 0x00, 0x00, 0xBB, /* 0x50-0x57 */ 0x00, 0x00, 0xC8, 0x00, 0x00, 0xBC, 0x00, 0x00, /* 0x58-0x5F */ 0xCC, 0x00, 0x00, 0xB9, 0x00, 0x00, 0xCB, 0x00, /* 0x60-0x67 */ 0x00, 0xCA, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, /* 0x68-0x6F */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7F */ 0xDF, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, /* 0x80-0x87 */ 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8F */ 0x00, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9F */ 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xF8-0xFF */ }; unsigned char *uni2asc_pg[256] = { page00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x00-0x07 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x08-0x0F */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x10-0x17 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x18-0x1F */ NULL, NULL, NULL, NULL, page25 /* 0x20-0x27 */ }; extern u_short fat_entry_size; extern u_long partsize; /* Partition size */ extern u_long partbgnaddr; /* Partition beginning */ extern u_long partendaddr; /* Partition ending */ extern u_int sectorcount; /* Number of sectors in this partition */ extern char nullext[]; int dbg = 1; static dirhash_t *dirhash[DIRHASHSIZE]; static char skip_chars[] = ".:\"?<>| "; static char bad_chars[] = "*?<>|\":/\\"; static char replace_chars[] = "[];,+="; /* *----------------------------------------------------------------------------- * vfat_update_disk_fat() * This routine writes out the in-core fat to disk. *----------------------------------------------------------------------------- */ int vfat_update_disk_fat(dfs_t *dfs) { int i; int error; int bad_fat_count = 0; if (!dfs->dirtyfat) return (0); lseek(dfs->dfs_fd, dfs->dfs_fataddr, 0); for (i = 0; i < dfs->dfs_bp.bp_fatcount; i++) { if (write(dfs->dfs_fd, dfs->dfs_fat, dfs->dfs_fatsize) < 0) { error = errno; bad_fat_count++; lseek(dfs->dfs_fd, dfs->dfs_fataddr+dfs->dfs_fatsize*(i + 1), 0); } } if (bad_fat_count == dfs->dfs_bp.bp_fatcount) return (error); dfs->dirtyfat = FALSE; return 0; } /* *----------------------------------------------------------------------------- * vfat_update_disk_root() * This routine writes out the in-core root to disk. *----------------------------------------------------------------------------- */ int vfat_update_disk_root(dfs_t *dfs) { if (!dfs->dirtyrootdir) return (0); lseek(dfs->dfs_fd, dfs->dfs_rootaddr, 0); if (write(dfs->dfs_fd, &dfs->dfs_root->d_dir[2], (dfs->dfs_rootsize-2*DIR_ENTRY_SIZE)) < 0) return (errno); dfs->dirtyrootdir = FALSE; return (0); } /* *----------------------------------------------------------------------------- * vfat_create_sname() * This routine is used to convert a long name into a short name. * NOTE: * If the lname can directly be used as sname, sflag = 1. * If the lname can't directly be used as sname, sflag = 0. *----------------------------------------------------------------------------- */ int vfat_create_sname(dnode_t *dp, char *lname, char *sname, int *sflag) { file_t f; char *ip, *op; char *lname_ext; char msdos_name[13]; char base[NAME_LEN+1], ext[EXTN_LEN+1]; int i, error, length, blen, elen; printf(" vfat_create_sname()\n"); *sflag = 0; length = strlen(lname); if (length && lname[length-1] == ' ') return (ERROR); if (length <= MSDOS_NAME+1){ /* * Attempt to directly use this as a shortname. * Convert lowercase to uppercase and try it. */ for (i = 0, ip = lname, op = msdos_name; i < length; i++,ip++,op++){ if (*ip >= 'a' && *ip <= 'z') *op = *ip-32; else *op = *ip; } error = vfat_format_sname(msdos_name, sname, length); if (!error){ error = vfat_dir_getent_sname(dp, msdos_name, &f); if (error != ENOENT) return (ERROR); *sflag = 1; return (0); } } vfat_type_lname(lname, &lname_ext, &length); vfat_compose_base(lname, lname_ext, length, base, &blen); vfat_compose_ext( lname, lname_ext, length, ext, &elen); if (blen == 0) return (ERROR); error = vfat_compose_sname(dp, msdos_name, sname, base, blen, ext, elen); return (error); } /* *----------------------------------------------------------------------------- * vfat_type_lname() * This routine is used to determine type of long name. * For type A: extension need not be created. * For type B: extension need be created. * - Type A: (XXXXXX, XXXXX., ...XXX) * - Type B: (XXX.XX) * Output: * - Type A: (lname_ext == 0, lname_size = len(lname)) * - Type B: (lname_ext != 0, lname_size = x) *----------------------------------------------------------------------------- */ int vfat_type_lname(char *lname, char **lname_ext, int *lname_size) { int length; char *t_bgn, *t_end, *t_ext; length = *lname_size; t_ext = t_end = &lname[length]; while (--t_ext >= lname){ if (*t_ext == '.'){ if (t_ext == t_end-1){ *lname_size = length; t_ext = 0; } break; } } if (t_ext == lname-1){ *lname_size = length; t_ext = 0; } else if (t_ext){ for (t_bgn = &lname[0]; t_bgn < t_ext; t_bgn++){ if (!strchr(skip_chars, *t_bgn)) break; } if (t_bgn != t_ext){ *lname_size = t_ext-lname; t_ext++; } else { *lname_size = length; t_ext = 0; } } *lname_ext = t_ext; return (0); } /* *----------------------------------------------------------------------------- * vfat_compose_base() * This routine accepts a long name, a pointer to the start of the extension * as well as size (which indicates number of characters to be scanned to form * the base), and then composes a base, and calculates its base length. *----------------------------------------------------------------------------- */ int vfat_compose_base(char *lname, char *lname_ext, int lname_size, char *base, int *baselen) { int blen; char *ip, *op; printf(" vfat_compose_base() \n"); for (blen = 0, ip = lname, op = base; blen < NAME_LEN && lname_size; ip++, lname_size--){ if (!strchr(skip_chars, *ip)){ if (*ip >= 'a' && *ip <= 'z') *op = *ip-32; else *op = *ip; if (strchr(replace_chars, *ip)) *op = '_'; op++; blen++; } } *baselen = blen; base[blen] = '\0'; return (0); } /* *----------------------------------------------------------------------------- * vfat_compose_ext() * This routine accepts a long name, a pointer to the start of the extension * and then composes an extension, and calculates its extension length. *----------------------------------------------------------------------------- */ int vfat_compose_ext(char *lname, char *lname_ext, int lname_size, char *ext, int *extlen) { int elen; char *ip, *op; printf(" vfat_compose_ext() \n"); if (lname_ext == 0){ *extlen = 0; return (0); } for (elen = 0, ip = lname_ext, op = ext; elen < EXTN_LEN && *ip != '\0'; ip++){ if (!strchr(skip_chars, *ip)){ if (*ip >= 'a' && *ip <= 'z') *op = *ip-32; else *op = *ip; if (strchr(replace_chars, *ip)) *op = '_'; op++; elen++; } } *extlen = elen; ext[elen] = '\0'; return (0); } /* *----------------------------------------------------------------------------- * vfat_compose_sname() * This routine accepts the extracted base, ext and then attempts to compose * a shortname, trying each time to see that there is no conflict. *----------------------------------------------------------------------------- */ int vfat_compose_sname(dnode_t *dp, char *sname1, char *sname2, char *base, int blen, char *ext, int elen) { file_t f; char tilde[NAME_LEN]; int count, size; int total, error, spaces; printf(" vfat_compose_sname()\n"); count = 0; error = 0; sname1[blen] = '.'; strcpy(sname1, base); strcpy(sname1+blen+1, ext); spaces = NAME_LEN-blen; total = blen+elen+1; while (error != ENOENT){ count++; if (count == 10000000) return (ERROR); sprintf(tilde, "%d", count); size = strlen(tilde); if (spaces < size+1){ blen -= (size+1-spaces); spaces = (size+1); } strncpy(sname1, base, blen); sname1[blen] = '~'; strcpy(sname1+blen+1, tilde); sname1[blen+size+1] = '.'; strcpy(sname1+blen+size+2, ext); total = blen+elen+size+2; error = vfat_format_sname(sname1, sname2, total); if (!error){ printf(" ATTEMPT: %s\n", vfat_print11(sname2)); error = vfat_dir_getent_sname(dp, sname2, &f); } } printf(" SUCCESS: %s\n", vfat_print11(sname2)); return (0); } /* *----------------------------------------------------------------------------- * vfat_format_sname() * This routine accepts a short name and attempts to convert it into a MSDOS * name; If this conversion isn't possible, an error is returned. If it *is* * possible, the corresponding MSDOS name is returned in 'sname2'. *----------------------------------------------------------------------------- */ int vfat_format_sname(char *sname1, char *sname2, int len) { int spc_flg; char ch, *t1, *t2; printf(" vfat_format_sname() \n"); ch = 0; spc_flg = 1; for (t1 = sname1, t2 = sname2; len && t2-sname2 < NAME_LEN; t2++){ ch = *t1++; len--; if (ch == '.') break; if (strchr(bad_chars, ch)) return (ERROR); if (strchr(replace_chars, ch)) return (ERROR); if (ch < ' ' || ch == ':' || ch == '\\') return (ERROR); spc_flg = (ch == ' '); /* Test Return */ if (spc_flg) return (ERROR); *t2 = (ch >= 'a' && ch <= 'z') ? ch-32:ch; } if (spc_flg) return (ERROR); if (len && ch != '.'){ ch = *t1++; len--; if (ch != '.') return (ERROR); } while (ch != '.' && len--) ch = *t1++; if (ch == '.'){ while (t2-sname2 < NAME_LEN) *t2++ = ' '; while (len > 0 && t2-sname2 < MSDOS_NAME){ ch = *t1++; len--; if (strchr(bad_chars, ch)) return (ERROR); if (strchr(replace_chars, ch)) return (ERROR); if (ch < ' ' || ch == ':' || ch == '\\' || ch == '.') return (ERROR); spc_flg = (ch == ' '); /* Test Return */ if (spc_flg) return (ERROR); *t2++ = (ch >= 'a' && ch <= 'z') ? ch-32:ch; } if (spc_flg) return (ERROR); if (len) return (ERROR); } while (t2-sname2 < MSDOS_NAME) *t2++ = ' '; return (0); } /* *----------------------------------------------------------------------------- * vfat_isvalid_lname() * This routine is used to check if a long name is valid or not. * If lname is valid, returns 0. * If lname isn't valid, returns 1. *----------------------------------------------------------------------------- */ int vfat_isvalid_lname(char *lname, int lname_len) { char ch; int i; if (lname_len && lname[lname_len-1] == ' ') return (ERROR); if (lname_len >= 256) return (ERROR); for (i = 0; i < lname_len; i++){ ch = lname[i]; if (strchr(bad_chars, ch)) return (ERROR); } return (0); } /* *----------------------------------------------------------------------------- * vfat_dir_lookup() * This routine accepts a node pointer to a directory entry, and looks into * the directory cache hash-tbl and returns the directory entry associated * with this file. * MAPS: (file's dp) => (file's file_t) * RETURNS: * (0) : If directory entry was successfully returned, and file_t. * (-1) : If directory entry wasn't successfully returned. *----------------------------------------------------------------------------- */ int vfat_dir_lookup(dnode_t *dp, file_t *fp) { u_short offset; u_short cluster; dnode_t *dirp; dirhash_t *dh; offset = OFFSET(dp->d_fno); cluster = CLUSTER(dp->d_fno); for (dh = DIRHASH(cluster); dh != NULL; dh = dh->next){ if (dh->cluster == cluster){ dirp = dh->dnode; fp->f_offset = offset; copy_dir_to_fp(dirp, fp); return (0); } } return (-1); } /* *----------------------------------------------------------------------------- * vfat_dir_getent_sname() * This routine accepts a directory node pointer and searches for an entry * inside it that matches the given shortname. * MAPS: (file's parent dp, sname) => (file's file_t) *----------------------------------------------------------------------------- */ int vfat_dir_getent_sname(dnode_t *dp, char *sname, file_t *fp) { return (vfat_dir_generic(dp, MODE_BRK, sname, fp, dirent_cmp_sname)); } /* *----------------------------------------------------------------------------- * vfat_dir_getent_lname() * This routine accepts a directory node pointer and searches for an entry * inside it that matches the given longname. * MAPS: (file's parent dp, lname) => (file's file_t) *----------------------------------------------------------------------------- */ int vfat_dir_getent_lname(dnode_t *dp, char *lname, file_t *fp) { return (vfat_dir_generic(dp, MODE_BRK, lname, fp, dirent_cmp_lname)); } /* *----------------------------------------------------------------------------- * vfat_dir_generic() * This routine accepts a directory node pointer and a function that is to * be invoked on each directory entry that is scanned. On success, this routine * might or might not return to the user depending upon "mode". * MODE = MODE_BRK => stop once func() returns 0, continue otherwise. * MODE = MODE_CNT => continue all through. *----------------------------------------------------------------------------- */ int vfat_dir_generic(dnode_t *dp, int mode, char *aux, file_t *fp, int (*func)(file_t *, char *)) { slot_t *sp; dfile_t *de, *de_bgn, *de_end; int id, error; int state, ret; int de_type; int expect_slotid, cluster; int dents_perclust; if (dp->d_dir == NULL){ error = vfat_dir_read(dp); if (error) return (error); } /* * Set states. */ state = ST_INIT; fp->f_nentries = 0; expect_slotid = -1; CLEAR_SLOTS(fp); /* * Start scanning all the directory entries * that are present in this parent directory. */ de_bgn = dp->d_dir; de_end = de_bgn+dp->d_size/DE_SIZ-1; for (de = de_bgn; de < de_end+1; de++){ if (de->df_name[0] == LAST_ENTRY) break; de_type = vfat_dirent_type(de); /* * Whenever we're in ST_INIT and we see * a directory entry, we store its cluster * and offset, and place it in "fp". */ if (state == ST_INIT){ fp->f_offset = de-de_bgn; if (dp->d_fno == ROOTFNO) fp->f_cluster = ROOT_CLUSTER; else fp->f_cluster = to_cluster(dp, fp->f_offset); } if (state == ST_INIT && de_type == DE_DIRENT){ fp->f_nentries = 0; COPY_SLOT_TO_FP(fp, de, 0); /* * Finished reading in one dir entry. * Execute generic function on it. */ ret = (*func)(fp, aux); if (mode == MODE_BRK && ret == 0) return (ret); goto reset; } else if (state == ST_INIT && de_type == DE_SLOT){ /* * This is the first slot that we're seeing * that might indicate the beginning of a * long file name. The first slot id has to * be extracted. */ sp = (slot_t *) de; id = sp->sl_id & 0xBF; fp->f_nentries = id; COPY_SLOT_TO_FP(fp, de, id); if (id == 1){ state = ST_EXPECT_DIRENT; continue; } else { state = ST_EXPECT_SLOT; expect_slotid = id-1; continue; } } else if (state == ST_EXPECT_SLOT && de_type == DE_SLOT){ sp = (slot_t *) de; id = sp->sl_id; if (id != expect_slotid) goto reset; COPY_SLOT_TO_FP(fp, de, id); if (id == 1){ state = ST_EXPECT_DIRENT; expect_slotid = -1; continue; } else { state = ST_EXPECT_SLOT; expect_slotid -= 1; continue; } } else if (state == ST_EXPECT_DIRENT && de_type == DE_DIRENT){ COPY_SLOT_TO_FP(fp, de, 0); /* * Finished reading one directory entry. * Execute function passed, on it. */ ret = (*func)(fp, aux); if (mode == MODE_BRK && ret == 0) return (ret); goto reset; } else goto reset; reset: state = ST_INIT; fp->f_nentries = 0; expect_slotid = -1; } /* * A return from this point implies a failure. * or that the func passed hasn't executed with * any success or "BRK"'ed out. */ return (ENOENT); } /* *----------------------------------------------------------------------------- * vfat_dirent_read_disk() * This routine is used to read a particular file entry from disk. * INPUT: (fp->f_offset, fp->f_cluster) are only filled. * NOTE: A particular file entry could be spread across more than one cluster. *----------------------------------------------------------------------------- */ int vfat_dirent_read_disk(dfs_t *dfs, file_t *fp) { int error; slot_t *sp; dfile_t *de; dfile_t *de_bgn, *de_end; int state; int nread, id, expect_slotid; int nentries, de_per_clust, de_type; u_short offset, noffset; u_short cluster, ncluster; u_char *cbuf; de_per_clust = DIR_ENTRY_PER_CLUSTER(dfs); CLEAR_SLOTS(fp); offset = fp->f_offset; cluster = fp->f_cluster; cbuf = safe_malloc(dfs->dfs_clustersize); error = vfat_clust_read(dfs, DISK_ADDR(dfs, cluster), cbuf); if (error) goto error; state = ST_INIT; expect_slotid = -1; noffset = offset % de_per_clust; de_bgn = (dfile_t *) cbuf; de_end = de_bgn+de_per_clust-1; de = de_bgn+noffset; de_type= vfat_dirent_type(de); /* Take a peek at the directory entry at this offset */ /* We then decide whether or not its part of a lname */ if (de_type == DE_DIRENT){ /* We've been asked to retrive a short name */ fp->f_nentries = 0; COPY_SLOT_TO_FP(fp, de, 0); goto found_dirent; } else if (de_type == DE_FREE){ /* We're looking at a blank directory entry */ goto error; } /* We see the beginning of a long directory entry */ /* This might or might not be spread over two clusts */ sp = (slot_t *) de; id = sp->sl_id & 0xBF; fp->f_nentries = nentries = id; if (nentries == 1){ /* We now expect to see a directory entry */ state = ST_EXPECT_DIRENT; expect_slotid = -1; } else { /* We now expect to see a slot */ state = ST_EXPECT_SLOT; expect_slotid = nentries-1; } /* Read all the slots that're part of this entry */ /* that are present inside this partic. cluster */ de++; while (de <= de_end){ de_type = vfat_dirent_type(de); if (state == ST_EXPECT_DIRENT && de_type == DE_DIRENT){ COPY_SLOT_TO_FP(fp, de, 0); goto found_dirent; } else if (state == ST_EXPECT_SLOT && de_type == DE_SLOT){ sp = (slot_t *) de; id = sp->sl_id; if (id != expect_slotid) goto error; COPY_SLOT_TO_FP(fp, de, id); if (id == 1){ state = ST_EXPECT_DIRENT; expect_slotid = -1; } else { state = ST_EXPECT_SLOT; expect_slotid -= 1; } } else goto error; de++; } /* Duh! This damned directory entry is part of a lname */ /* and it spills over to the next cluster in this dir */ /* Retrieve this next cluster, and keep grabbing slots */ ncluster = (*dfs->dfs_readfat)(dfs, cluster); if (end_cluster(dfs, ncluster)){ /* End of directory reached */ goto error; } error = vfat_clust_read(dfs, DISK_ADDR(dfs, ncluster), cbuf); if (error) goto error; de_bgn = (dfile_t *) cbuf; de_end = de_bgn+de_per_clust-1; de = de_bgn; while (de <= de_end){ de_type = vfat_dirent_type(de); if (state == ST_EXPECT_DIRENT && de_type == DE_DIRENT){ COPY_SLOT_TO_FP(fp, de, 0); goto found_dirent; } else if (state == ST_EXPECT_SLOT && de_type == DE_SLOT){ sp = (slot_t *) de; id = sp->sl_id; if (id != expect_slotid) goto error; COPY_SLOT_TO_FP(fp, de, id); if (id == 1){ state = ST_EXPECT_DIRENT; expect_slotid = -1; } else { state = ST_EXPECT_SLOT; expect_slotid -= 1; } } else goto error; de++; } error: free (cbuf); CLEAR_SLOTS(fp); return (1); found_dirent: free (cbuf); return (0); } /* *----------------------------------------------------------------------------- * vfat_dir_writent() * This routine is used to write a particular file entry into a directory. * NOTE: We have to handle the case wherein a file entry spills into next clust *----------------------------------------------------------------------------- */ int vfat_dir_writent(dnode_t *dp, file_t *fp) { int error; dfs_t *dfs; u_long daddr1; u_long daddr2; u_long clustadd; u_char *clustbuf; u_short offset, eoffset; u_short cluster, ncluster; int de_per_clust; int nextclusterflag; dfs = dp->d_dfs; if (dp->d_dir == NULL){ error = vfat_dir_read(dp); if (error) return (error); } /* * Copy file directory entry into dir. */ copy_fp_to_dir(dp, fp); if (fp->f_cluster == ROOT_CLUSTER){ error = vfat_update_root(dfs); return (error); } offset = fp->f_offset; eoffset = fp->f_offset+fp->f_nentries; cluster = fp->f_cluster; daddr1 = fp->f_offset-fp->f_offset % DIR_ENTRY_PER_CLUSTER(dfs); daddr2 = daddr1+DIR_ENTRY_PER_CLUSTER(dfs); /* Check to see if this file entry */ /* spills into next cluster or not */ if (eoffset >= daddr2) nextclusterflag = 1; else nextclusterflag = 0; if (!nextclusterflag){ /* No, we merely have to write out this cluster */ clustadd = DISK_ADDR(dfs, cluster); clustbuf = (u_char *) &dp->d_dir[daddr1]; error = vfat_clust_writ(dfs, clustadd, clustbuf); if (error) return (error); } else { /* Yes, we have to write out this and next cluster */ clustadd = DISK_ADDR(dfs, cluster); clustbuf = (u_char *) &dp->d_dir[daddr1]; error = vfat_clust_writ(dfs, clustadd, clustbuf); if (error) return (error); ncluster = (*dfs->dfs_readfat)(dfs, cluster); if (end_cluster(dfs, ncluster)) return (error); clustadd = DISK_ADDR(dfs, ncluster); clustbuf = (u_char *) &dp->d_dir[daddr2]; error = vfat_clust_writ(dfs, clustadd, clustbuf); if (error) return (error); } return (0); } /* *----------------------------------------------------------------------------- * vfat_dir_delent() * This routine is used to delete a particular file entry from a directory. * The file corresponding to the directory entry is also deleted from the fat. *----------------------------------------------------------------------------- */ int vfat_dir_delent(dnode_t *dp, file_t *fp) { dfs_t *dfs; int error; int nentries; u_short cluster; u_short ncluster; /* * Remove FAT chain corresponding to the file */ dfs = dp->d_dfs; cluster = START_CLUSTER(fp); do { ncluster = (*dfs->dfs_readfat)(dfs, cluster); (*dfs->dfs_writefat)(dfs, cluster, 0); dfs->dfs_freeclustercount++; cluster = ncluster; } while (!LAST_CLUSTER(dfs, cluster)); error = vfat_update_fat(dfs); if (error) return (ERR); fp->f_entries[0].df_name[0] = REUSABLE_ENTRY; for (nentries = fp->f_nentries; nentries; nentries--) fp->f_entries[nentries].df_name[0] = REUSABLE_ENTRY; error = vfat_dir_writent(dp, fp); if (error) return (ERR); fp->f_nentries = 0; return (0); } /* *----------------------------------------------------------------------------- * vfat_dir_nulent() * This routine is used to delete a particular file entry from a directory * without removing the file itself. *----------------------------------------------------------------------------- */ int vfat_dir_nulent(dnode_t *dp, file_t *fp) { dfs_t *dfs; int error; int nentries; u_short cluster; u_short ncluster; fp->f_entries[0].df_name[0] = REUSABLE_ENTRY; for (nentries = fp->f_nentries; nentries; nentries--) fp->f_entries[nentries].df_name[0] = REUSABLE_ENTRY; error = vfat_dir_writent(dp, fp); if (error) return (ERR); fp->f_nentries = 0; return (0); } /* *----------------------------------------------------------------------------- * vfat_dir_freent() * This routine accepts a pointer to a directory node and scans it looking for * "nentries" that are vacant and contiguous; If found, the cluster and offset * are returned; If not found, the directory file is expanded by one cluster. *----------------------------------------------------------------------------- */ int vfat_dir_freent(dnode_t *dp, int nentries, u_short *clst, u_short *off) { u_short lclst; u_short nclst; u_short tmpoff; dfs_t *dfs; dfile_t *de; dfile_t *de_bgn, *de_end; int de_type, error; int state, tmpoffset; int nfree, noffset; dfs = dp->d_dfs; if (dp->d_dir == NULL){ error = vfat_dir_read(dp); if (error) return (ERR); } /* * Root directory has a limited capacity, * The other directories don't have limits. */ if (dp->d_fno == ROOTFNO){ state = ST_INIT; nfree = 0; noffset= 0; de_bgn = dp->d_dir; de_end = de_bgn+dp->d_size/DE_SIZ-1; for (de = de_bgn; de < de_end+1; de++){ de_type = vfat_dirent_type(de); if (state == ST_INIT && de_type == DE_FREE){ nfree = 1; noffset = de-de_bgn; *clst = ROOT_CLUSTER; if (nfree == nentries+1){ *off = noffset; return (0); } state = ST_EXPECT_FREE; } else if (state == ST_EXPECT_FREE && de_type == DE_FREE){ nfree++; if (nfree == nentries+1){ *off = noffset; return (0); } state = ST_EXPECT_FREE; } else if (state == ST_EXPECT_FREE && de_type != DE_FREE){ nfree = 0; noffset = 0; *clst = 0; state = ST_INIT; } } return (ENOSPC); } else { state = ST_INIT; nfree = 0; noffset= 0; de_bgn = dp->d_dir; de_end = (de_bgn+dp->d_size/DE_SIZ-1); for (de = de_bgn; de < de_end+1; de++){ de_type = vfat_dirent_type(de); if (state == ST_INIT && de_type == DE_FREE){ nfree = 1; noffset = de-de_bgn; *clst = to_cluster(dp, noffset); if (nfree == nentries+1){ *off = noffset; return (0); } state = ST_EXPECT_FREE; } else if (state == ST_EXPECT_FREE && de_type == DE_FREE){ nfree++; if (nfree == nentries+1){ *off = noffset; return (0); } state = ST_EXPECT_FREE; } else if (state == ST_EXPECT_FREE && de_type != DE_FREE){ nfree = 0; noffset = 0; *clst = 0; state = ST_INIT; } else if (state == ST_INIT && de_type != DE_FREE){ nfree = 0; noffset = 0; *clst = 0; state = ST_INIT; } } /* We've reached the end of the directory file */ /* We have no vacant entries that are enough */ /* We have to expand the directry file by 1 */ /* Chain this cluster with the last in FAT */ /* Bzero the entire new cluster and write it */ /* (1) We might have already seen the beginning of a hole */ /* (2) We might not have seen the beginning of a hole */ nclst = vfat_free_fat(dfs); if (nclst == 0) return (ENOSPC); tmpoff = de-dp->d_dir; lclst = to_cluster(dp, tmpoff-1); (*dfs->dfs_writefat)(dfs, lclst, nclst); dp->d_size += dfs->dfs_clustersize; dp->d_dir = (dfile_t *) realloc(dp->d_dir, dp->d_size); if (!dp->d_dir){ syslog(LOG_ERR, "Out of memory"); exit(1); } bzero(&dp->d_dir[tmpoff], dfs->dfs_clustersize); vfat_clust_writ(dfs, DISK_ADDR(dfs, nclst), dfs->dfs_zerobuf); if (*clst == 0){ /* We return a hole that's entirely in the new clust */ *clst = nclst; *off = tmpoff; } else { /* We return a hole that began in a previous cluster */ *off = noffset; } } error = vfat_update_fat(dfs); return (0); } /* *----------------------------------------------------------------------------- * vfat_dirent_type * This routine sees a particular directory entry and returns: * - DE_FREE = free entry. * - DE_SLOT = slot entry associated with a directory entry. * - DE_DIRENT= directory entry. * - DE_LABEL = volume label. *----------------------------------------------------------------------------- */ int vfat_dirent_type(dfile_t *df) { if (df->df_name[0] == LAST_ENTRY || df->df_name[0] == REUSABLE_ENTRY) return (DE_FREE); else if (IS_LABEL(df)) return (DE_LABEL); else if (df->df_attribute == 0x0F && df->df_start[0] == 0x00 && df->df_start[1] == 0x00) return (DE_SLOT); else return (DE_DIRENT); } /* *----------------------------------------------------------------------------- * vfat_dirent_print() * This routine is used to print out a "file_t", it's lname/sname. *----------------------------------------------------------------------------- */ int vfat_dirent_print(file_t *fp) { char sname[12]; char lname[255]; vfat_dirent_upackname(fp, lname, sname); sname[11] = '\0'; printf(" Sname = %s nentries = %d ", sname, fp->f_nentries); printf(" clust = %d off = %d\n", fp->f_cluster, fp->f_offset); fflush(stdout); return (0); } /* *----------------------------------------------------------------------------- * vfat_dirent_packname() * This routine accepts a lname/sname and a "file_t" and proceeds to pack * these two names into it. * NOTE: * Input sflag = 1 => sname is to be used as real name, no slots needed. * Input sflag = 0 => lname is to be used as real name, slots are needed. *----------------------------------------------------------------------------- */ int vfat_dirent_packname(file_t *fp, char *lname, char *sname, int sflag) { slot_t *sp; dfile_t *de; u_char chksum; int end_flg; int i, num_slots; int lname_len, slot_id; char *s, *sbgn, *send, *send1, *send2; end_flg = 0; chksum = vfat_sname_chksum(sname); lname_len = strlen(lname); num_slots = (lname_len+12)/13; /* * Fill in directory entry. * This is the very first slot. */ de = fp->f_entries; strncpy(de->df_name, sname, 8); strncpy(de->df_ext, sname+8, 3); if (sflag) goto directly_use_sname; for (slot_id = num_slots; slot_id; slot_id--){ sp = (slot_t *) &fp->f_entries[slot_id]; sbgn = &lname[(slot_id-1)*13]; send1= &lname[slot_id*13-1]; send2= &lname[lname_len-1]; if (send1 < send2) send = send1; else send = send2; end_flg = 0; /* * Initialize the slot entry. * The last slot id is OR'd with 0x40. */ sp->sl_id = slot_id; if (slot_id == num_slots) sp->sl_id |= 0x40; sp->sl_attr = ATTRIB_EXTNDD; sp->sl_chksum = chksum; sp->sl_reserved = 0; sp->sl_start[0] = 0; sp->sl_start[1] = 0; /* * Break longname segment up into three parts. * Pack each part with its ucodes. * part1 = 5 chars: sbgn.....sbgn+4 * part2 = 6 chars: sbgn+5...sbgn+10 * part3 = 2 chars: sbgn+11..sbgn+12 */ for (s = sbgn, i = 0; s < sbgn+5; s++, i+= 2){ if (end_flg){ /* Go ahead and scribble 0xFF ucodes */ sp->sl_name0_4[i] = 0xFF; sp->sl_name0_4[i+1]= 0xFF; } else { if (s == send+1){ /* Set end flag */ /* Scribble 0x00 ucode and continue */ end_flg = 1; sp->sl_name0_4[i] = 0x00; sp->sl_name0_4[i+1] = 0x00; continue; } else { sp->sl_name0_4[i] = a2ucode1(*s); sp->sl_name0_4[i+1] = a2ucode2(*s); } } } for (s = sbgn+5, i = 0; s < sbgn+11; s++, i += 2){ if (end_flg){ /* Go ahead and scribble 0xFF ucodes */ sp->sl_name5_10[i] = 0xFF; sp->sl_name5_10[i+1]= 0xFF; } else { if (s == send+1){ /* Set end flag */ /* Scribble 0x00 ucode and continue */ end_flg = 1; sp->sl_name5_10[i] = 0x00; sp->sl_name5_10[i+1] = 0x00; continue; } else { sp->sl_name5_10[i] = a2ucode1(*s); sp->sl_name5_10[i+1] = a2ucode2(*s); } } } for (s = sbgn+11, i = 0; s < sbgn+13; s++, i += 2){ if (end_flg){ /* Go ahead and scribble 0xFF ucodes */ sp->sl_name11_12[i] = 0xFF; sp->sl_name11_12[i+1]= 0xFF; } else { if (s == send+1){ /* Set end flag */ /* Scribble 0x00 ucode and continue */ end_flg = 1; sp->sl_name11_12[i] = 0x00; sp->sl_name11_12[i+1] = 0x00; continue; } else { sp->sl_name11_12[i] = a2ucode1(*s); sp->sl_name11_12[i+1] = a2ucode2(*s); } } } } fp->f_nentries = num_slots; return (0); directly_use_sname: /* It looks like this file's long name */ /* is identical to the short name. We */ /* hence need no slots to pack the name*/ fp->f_nentries = 0; return (0); } /* *----------------------------------------------------------------------------- * vfat_dirent_upackname() * This routine accepts a "file_t" and extracts the lname/sname from inside it. *----------------------------------------------------------------------------- */ int vfat_dirent_upackname(file_t *fp, char *lname, char *sname) { slot_t *sp; dfile_t *de; int end_flg; int broken; int i, slot_id; char *t = lname; u_char chksum, byte1, byte2, ascii; u_short word; de = fp->f_entries; strncpy(sname, de->df_name,8); strncpy(sname+8,de->df_ext, 3); chksum = vfat_sname_chksum(sname); if (fp->f_nentries == 0){ to_unixname(de->df_name, de->df_ext, lname); return (0); } for (slot_id = 1; slot_id <= fp->f_nentries; slot_id++){ sp = (slot_t *) &fp->f_entries[slot_id]; /* Look at: sl_name0_4 */ for (i = 0; i < 10; i += 2){ byte1 = sp->sl_name0_4[i]; byte2 = sp->sl_name0_4[i+1]; if (byte1 == 0xFF || byte2 == 0xFF) return ERR; if (byte1 == 0x00 && byte2 == 0x00) goto end; word = (byte2 << 8) | (byte1); ascii = ucode2a(word, &end_flg); if (end_flg) goto end; *t++ = ascii; } /* Look at: sl_name5_10 */ for (i = 0; i < 12; i += 2){ byte1 = sp->sl_name5_10[i]; byte2 = sp->sl_name5_10[i+1]; if (byte1 == 0xFF || byte2 == 0xFF) return ERR; if (byte1 == 0x00 && byte2 == 0x00) goto end; word = (byte2 << 8) | (byte1); ascii = ucode2a(word, &end_flg); if (end_flg) goto end; *t++ = ascii; } /* Look at: sl_name11_12 */ for (i = 0; i < 4; i+= 2){ byte1 = sp->sl_name11_12[i]; byte2 = sp->sl_name11_12[i+1]; if (byte1 == 0xFF || byte2 == 0xFF) return ERR; if (byte1 == 0x00 && byte2 == 0x00) goto end; word = (byte2 << 8) | (byte1); ascii = ucode2a(word, &end_flg); if (end_flg) goto end; *t++ = ascii; } } end: *t = '\0'; /* * We need to perform a consistency check to * ensure that the long name does indeed map * to this short name. * Also check for invalid unicode detected (end == 2). */ broken = vfat_dirent_broken(fp); if (broken || (end_flg == 2)) { /* Merely return the short name as long name */ fp->f_nentries = 0; to_unixname(de->df_name, de->df_ext, lname); } return (0); error: return (ERR); } /* *----------------------------------------------------------------------------- * vfat_dirent_broken() * This routine takes a "file_t" and checks to see if the checksum holds good. * Returns (0) => checksum is intact. * Returns (1) => checksum is broken. *----------------------------------------------------------------------------- */ int vfat_dirent_broken(file_t *fp) { slot_t *sp; dfile_t *de; int id; u_char chksum; char sname[MSDOS_NAME]; if (fp->f_nentries == 0) return (0); de = &fp->f_entries[0]; strncpy(sname, de->df_name, 8); strncpy(sname+8, de->df_ext, 3); chksum = vfat_sname_chksum(sname); id = fp->f_nentries; while (id){ sp = (slot_t *) &fp->f_entries[id]; if (sp->sl_chksum != chksum) return (1); id--; } return (0); } /* *----------------------------------------------------------------------------- * dirent_cmp_sname() * This routine takes a file_t and compares it against a short name. * NOTE: sname has to be in dos format (11 chars). *----------------------------------------------------------------------------- */ int dirent_cmp_sname(file_t *fp, char *sname) { char sname2[11]; char lname[255]; vfat_dirent_upackname(fp, lname, sname2); if (dosname_cmp(sname, sname2)) return (0); return (1); } /* *----------------------------------------------------------------------------- * dirent_cmp_lname() * This routine takes a file_t and compares it against a long name. *----------------------------------------------------------------------------- */ int dirent_cmp_lname(file_t *fp, char *lname) { int ret; char sname[11]; char lname2[255]; vfat_dirent_upackname(fp, lname2, sname); if (fp->f_nentries == 0){ to_unixname(fp->f_entries[0].df_name, fp->f_entries[0].df_ext, sname); /* * Perform a case insensitive comparison between sname/lname */ ret = dosname_cmp_lname(sname, lname); if (ret) return (0); } else { /* * Perform a case insensitive comparison between lname/lname2 */ ret = dosname_cmp_lname(lname, lname2); if (ret) return (0); } return (1); } /* *----------------------------------------------------------------------------- * vfat_sname_chksum() * This routine computes the checksum of a sname. *----------------------------------------------------------------------------- */ u_char vfat_sname_chksum(char *sname) { int i; u_char sum; for (sum = i = 0; i < 11; i++) sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + sname[i]; return (sum); } /* *----------------------------------------------------------------------------- * vfat_dir_read() * This routine reads a directory into the directory cache. *----------------------------------------------------------------------------- */ int vfat_dir_read(dnode_t *dp) { char *bp; u_short cluster; dfs_t *dfs; dirhash_t *dh, **dhp; dfs = dp->d_dfs; dp->d_dir = (dfile_t *)safe_malloc(dp->d_size); cluster = dp->d_start; bp = (char *) dp->d_dir; do { lseek(dfs->dfs_fd, DISK_ADDR(dfs, cluster), 0); if (read(dfs->dfs_fd, bp, dfs->dfs_clustersize) < 0) return errno; dhp = &DIRHASH(cluster); dh = (dirhash_t *)safe_malloc(sizeof *dh); dh->dnode = dp; dh->cluster= cluster; dh->next = *dhp; *dhp = dh; bp += dfs->dfs_clustersize; cluster = (*dfs->dfs_readfat)(dfs, cluster); } while (!LAST_CLUSTER(dfs, cluster)); return (0); } /* *----------------------------------------------------------------------------- * vfat_dir_write() * This routine purges a directory cache to disk. *----------------------------------------------------------------------------- */ int vfat_dir_write(dnode_t *dp) { int i; dirhash_t *dh, **dhp; if (dp->d_dir == NULL) return (0); for (i = 0; i < DIRHASHSIZE; i++) { dhp = &dirhash[i]; while ((dh = *dhp) != NULL) { if (dh->dnode == dp) { *dhp = dh->next; free(dh); continue; } dhp = &dh->next; } } free(dp->d_dir); dp->d_dir = NULL; return (0); } /* *----------------------------------------------------------------------------- * vfat_clust_writ() *----------------------------------------------------------------------------- */ int vfat_clust_writ(dfs_t *dfs, u_long daddr, u_char *clustbuf) { int nwrite; lseek(dfs->dfs_fd, daddr, SEEK_SET); nwrite = write(dfs->dfs_fd, clustbuf, dfs->dfs_clustersize); if (nwrite != dfs->dfs_clustersize) return (1); return (0); } /* *----------------------------------------------------------------------------- * vfat_clust_read() *----------------------------------------------------------------------------- */ int vfat_clust_read(dfs_t *dfs, u_long daddr, u_char *clustbuf) { int nread; lseek(dfs->dfs_fd, daddr, SEEK_SET); nread = read(dfs->dfs_fd, clustbuf, dfs->dfs_clustersize); if (nread != dfs->dfs_clustersize) return (1); return (0); } /* *----------------------------------------------------------------------------- * vfat_update_fat() *----------------------------------------------------------------------------- */ int vfat_update_fat(dfs_t *dfs) { dfs->dirtyfat = TRUE; return (0); } /* *----------------------------------------------------------------------------- * vfat_update_root() *----------------------------------------------------------------------------- */ int vfat_update_root(dfs_t *dfs) { dfs->dirtyrootdir = TRUE; return (0); } /* *----------------------------------------------------------------------------- * vfat_free_fat() *----------------------------------------------------------------------------- */ u_short vfat_free_fat(dfs_t *dfs) { u_short i; static u_short lcluster_assigned = 1; if (dfs->dfs_freeclustercount == 0) return 0; for (i = lcluster_assigned + 1; i < dfs->dfs_clustercount + 2; i++) { if ((*dfs->dfs_readfat)(dfs, i) == 0) { (*dfs->dfs_writefat)(dfs, i, dfs->dfs_endclustermark); dfs->dfs_freeclustercount--; lcluster_assigned = i; return i; } } for (i = 2; i <= lcluster_assigned; i++) { if ((*dfs->dfs_readfat)(dfs, i) == 0) { (*dfs->dfs_writefat)(dfs, i, dfs->dfs_endclustermark); dfs->dfs_freeclustercount--; lcluster_assigned = i; return i; } } panic(" vfat_free_fat: cannot allocate a FAT entry"); return (0); } /* *----------------------------------------------------------------------------- * copy_dir_to_fp() * NOTE: The structure fp's field fp->f_offset ought to be filled. *----------------------------------------------------------------------------- */ int copy_dir_to_fp(dnode_t *dp, file_t *fp) { slot_t *sp; dfile_t *de; int nentries; int de_type, id; de = &dp->d_dir[fp->f_offset]; de_type = vfat_dirent_type(de); if (de_type == DE_SLOT){ sp = (slot_t *) de; nentries = sp->sl_id & 0xBF; for (id = nentries; id >= 0; id--, de++){ COPY_SLOT_TO_FP(fp, de, id); } fp->f_nentries = nentries; } else { COPY_SLOT_TO_FP(fp, de, 0); fp->f_nentries = 0; } return (0); } /* *----------------------------------------------------------------------------- * xtract_fp_from_root() * This routine accepts a chunk of memory constituting the root, and an offset * that indexes into it; It then starts at this offset and proceeds to piece * together a "file_t". * NOTE: offset = dfile_t index over entire directory. *----------------------------------------------------------------------------- */ int xtract_fp_from_root(dfs_t *dfs, dfile_t *rootbuf, u_short offset, file_t *fp) { slot_t *sp; dfile_t *de; int nentries; int de_type, id; de = &rootbuf[offset]; de_type = vfat_dirent_type(de); if (de_type == DE_SLOT){ sp = (slot_t *) de; nentries = sp->sl_id & 0xBF; for (id = nentries; id >= 0; id--, de++){ COPY_SLOT_TO_FP(fp, de, id); } fp->f_nentries = nentries; } else { COPY_SLOT_TO_FP(fp, de, 0); fp->f_nentries = 0; } return (0); } /* *----------------------------------------------------------------------------- * copy_fp_to_dir() * NOTE: The structure fp ought to be filled. *----------------------------------------------------------------------------- */ int copy_fp_to_dir(dnode_t *dp, file_t *fp) { dfile_t *de; int id, nentries; de = &dp->d_dir[fp->f_offset]; nentries = fp->f_nentries; for (id = nentries; id >= 0; id--, de++){ COPY_SLOT_FROM_FP(fp, de, id); } return (0); } /* *----------------------------------------------------------------------------- * vfat_copy_attributes() * This routine is used to copy the attributes: (time, date, size, start). *----------------------------------------------------------------------------- */ int vfat_copy_attributes(file_t *fp1, file_t *fp2) { dfile_t *df1 = fp1->f_entries; dfile_t *df2 = fp2->f_entries; df2->df_attribute = df1->df_attribute; df2->df_time[0] = df1->df_time[0]; df2->df_time[1] = df1->df_time[1]; df2->df_date[0] = df2->df_date[0]; df2->df_date[1] = df2->df_date[1]; df2->df_size[0] = df1->df_size[0]; df2->df_size[1] = df1->df_size[1]; df2->df_size[2] = df1->df_size[2]; df2->df_size[3] = df1->df_size[3]; df2->df_start[0] = df1->df_start[0]; df2->df_start[1] = df1->df_start[1]; return (0); } /* *----------------------------------------------------------------------------- * a2ucode1() * This routine is used to convert a char into its first ucode. *----------------------------------------------------------------------------- */ u_char a2ucode1(char ch) { return (a2uni[ch].uni1); } /* *----------------------------------------------------------------------------- * a2ucode() * This routine is used to convert a char into its second ucode. *----------------------------------------------------------------------------- */ u_char a2ucode2(char ch) { return (a2uni[ch].uni2); } /* *----------------------------------------------------------------------------- * ucode2a() * This routine is used to convert a unicode into its ascii char. * * (*end) set to: 0 - valid ascii character returned * 1 - 'end' unicode detected * 2 - invalid unicode detected *----------------------------------------------------------------------------- */ u_char ucode2a(u_short word, int *end) { u_char ret; u_char byte1, byte2; u_char *uni_page; u_char page, pg_off, ascii; byte1 = (word & 0xFF00) >> 8; byte2 = (word & 0x00FF); pg_off = byte2; page = byte1; *end = 0; if (pg_off == 0 && page == 0) { *end = 1; return 0; } uni_page = uni2asc_pg[page]; if (uni_page == NULL) { *end = 2; return 0; } ascii = uni_page[pg_off]; ret = ascii ? ascii : '?'; return (ret); } /* *----------------------------------------------------------------------------- * to_dostime() * This routine chances time in UNIX format to DOS format * The DOS time format is as follow: * Bits Contents * 0x0-0x4 second in 2 seconds increment (0-29) * 0x5-0xa minutes (0-59) * 0xb-0xf hours (0-23) * * the DOS date format is as follow: * Bits Contents * 0x0-0x4 days of month (1-31) * 0x5-0x8 month (1-12) * 0x9-0xf year (relative to 1980) *----------------------------------------------------------------------------- */ void to_dostime(u_char *d_date, u_char *d_time, time_t *u_time) { struct tm tm; tm = *localtime(u_time); d_date[0] = tm.tm_mday | (((tm.tm_mon + 1) & 0x7) << 5); d_date[1] = ((tm.tm_mon + 1) >> 3) | ((tm.tm_year - 80) << 1); d_time[0] = (tm.tm_sec / 2) | ((tm.tm_min & 0x7) << 5); d_time[1] = (tm.tm_min >> 3) | (tm.tm_hour << 3); return; } /* *----------------------------------------------------------------------------- * to_unixtime() * This routine changes time in DOS format to UNIX format. *----------------------------------------------------------------------------- */ void to_unixtime(u_char *d_date, u_char *d_time, time_t *u_time) { struct tm tm; tm.tm_sec = (d_time[0] & 0x1f) * 2; tm.tm_min = ((d_time[1] & 0x7) << 3) | (d_time[0] >> 5); tm.tm_hour = d_time[1] >> 3; tm.tm_mday = d_date[0] & 0x1f; tm.tm_mon = ((d_date[0] >> 5) | ((d_date[1] & 0x1) << 3)) - 1; tm.tm_year = (d_date[1] >> 1) + 80; tm.tm_isdst = 1; *u_time = mktime(&tm); return; } /* *----------------------------------------------------------------------------- * set_attribute() *----------------------------------------------------------------------------- */ int set_attribute(dnode_t *dp, int archive_attrib) { int error; dfs_t *dfs; dnode_t *pdp; file_t f; dfile_t *df; u_int size; u_short offset; u_short cluster; dfs = dp->d_dfs; if (dp->d_fno == ROOTFNO) return (0); error = dos_getnode(dfs, dp->d_pfno, &pdp); if (error) return (error); if (pdp->d_dir == NULL){ error = vfat_dir_read(pdp); if (error) goto set_attribute_done; } f.f_offset = offset = OFFSET(dp->d_fno); f.f_cluster = cluster = CLUSTER(dp->d_fno); copy_dir_to_fp(pdp, &f); df = &(f.f_entries[0]); if (dp->d_ftype == NFREG){ size = DF_SIZE(df); error = expand_file(dfs, dp->d_start, size, dp->d_size); if (error) goto set_attribute_done; df->df_size[0] = (dp->d_size & 0xff); df->df_size[1] = (dp->d_size >> 8) & 0xff; df->df_size[2] = (dp->d_size >> 16) & 0xff; df->df_size[3] = (dp->d_size >> 24) & 0xff; /* * No readonly directory in DOS * archive attribute applies to regular files only */ if (dp->d_mode & WRITE_MODE) df->df_attribute &= ~ATTRIB_RDONLY; else df->df_attribute |= ATTRIB_RDONLY; df->df_attribute |= archive_attrib; } to_dostime(df->df_date, df->df_time, &dp->d_time); error = vfat_dir_writent(pdp, &f); set_attribute_done: dos_putnode(pdp); return (error); } /* *----------------------------------------------------------------------------- * expand_file() *----------------------------------------------------------------------------- */ int expand_file(dfs_t *dfs, u_short start, u_int o_size, u_int n_size) { int i; u_short lcluster; u_short ncluster; /* * Convert size in bytes to size in clusters. * In DOS, every file must has atleast one cluster */ o_size = (o_size + dfs->dfs_clustersize - 1) / dfs->dfs_clustersize; if (o_size == 0) o_size = 1; n_size = (n_size + dfs->dfs_clustersize - 1) / dfs->dfs_clustersize; if (n_size == 0) n_size = 1; if (o_size == n_size) /* no change */ return 0; /* Truncate */ if (o_size > n_size) { ncluster = start; for (i = n_size - 1; i > 0; i--) ncluster = (*dfs->dfs_readfat)(dfs, ncluster); lcluster = ncluster; ncluster = (*dfs->dfs_readfat)(dfs, ncluster); (*dfs->dfs_writefat)(dfs, lcluster, dfs->dfs_endclustermark); do { lcluster = ncluster; ncluster = (*dfs->dfs_readfat)(dfs, ncluster); (*dfs->dfs_writefat)(dfs, lcluster, 0); /* Increment free cluster count */ dfs->dfs_freeclustercount++; } while (!LAST_CLUSTER(dfs, ncluster)); return (vfat_update_fat(dfs)); } /* Expand */ if (n_size - o_size > dfs->dfs_freeclustercount) return (ENOSPC); lcluster = start; for (i = o_size - 1; i > 0; i--) lcluster = (*dfs->dfs_readfat)(dfs, lcluster); for (i = n_size - o_size; i > 0; i--) { ncluster = vfat_free_fat(dfs); (*dfs->dfs_writefat)(dfs, lcluster, ncluster); lcluster = ncluster; } return (vfat_update_fat(dfs)); } /* *----------------------------------------------------------------------------- * subdir_size() * This routine is used to find the size, in bytes, of a specified directory. *----------------------------------------------------------------------------- */ u_int subdir_size(dnode_t *dp) { u_int count; u_short cluster; dfs_t *dfs = dp->d_dfs; cluster = dp->d_start; count = 0; do { count++; cluster = (*dfs->dfs_readfat)(dfs, cluster); } while (!LAST_CLUSTER(dfs, cluster)); return (dfs->dfs_clustersize*count); } /* *----------------------------------------------------------------------------- * to_cluster() * This routine is used to locate the cluster where a directory entry with * a given offset is. *----------------------------------------------------------------------------- */ u_short to_cluster(dnode_t *dp, u_short offset) { int i; u_short cluster; dfs_t *dfs = dp->d_dfs; cluster = dp->d_start; for (i = offset / DIR_ENTRY_PER_CLUSTER(dfs); i > 0; i--) cluster = (*dfs->dfs_readfat)(dfs, cluster); return (cluster); } /* *----------------------------------------------------------------------------- * readfat12() *----------------------------------------------------------------------------- */ u_short readfat12(dfs_t *dfs, u_short cluster) { int i; i = cluster * 12 / 8; if (cluster % 2) return (dfs->dfs_fat[i] >> 4) | (dfs->dfs_fat[i + 1] << 4); return dfs->dfs_fat[i] | ((dfs->dfs_fat[i + 1] & 0xf) << 8); } /* *----------------------------------------------------------------------------- * readfat16() *----------------------------------------------------------------------------- */ u_short readfat16(dfs_t *dfs, u_short cluster) { int i; i = cluster * 2; return (dfs->dfs_fat[i] | (dfs->dfs_fat[i + 1] << 8)); } /* *----------------------------------------------------------------------------- * writefat12() *----------------------------------------------------------------------------- */ void writefat12(dfs_t *dfs, u_short cluster, u_short value) { int i; i = cluster * 12 / 8; if (cluster % 2) { dfs->dfs_fat[i] = (dfs->dfs_fat[i] & 0xf) | ((value & 0xf) << 4); dfs->dfs_fat[i + 1] = value >> 4; } else { dfs->dfs_fat[i] = value & 0xff; dfs->dfs_fat[i + 1] = (dfs->dfs_fat[i + 1] & 0xf0) | (value >> 8); } return; } /* *----------------------------------------------------------------------------- * writefat16() *----------------------------------------------------------------------------- */ void writefat16(dfs_t *dfs, u_short cluster, u_short value) { int i; i = cluster * 2; dfs->dfs_fat[i] = value & 0xff; dfs->dfs_fat[i + 1] = value >> 8; return; } /* *----------------------------------------------------------------------------- * cache_dirty() *----------------------------------------------------------------------------- */ int cache_dirty() { int i ; for (i = 0; i < trkcache.dirtymaskcnts; i++) if (trkcache.dirty[i]) return (TRUE); return (FALSE); } /* *----------------------------------------------------------------------------- * set_dirty() *----------------------------------------------------------------------------- */ int set_dirty(int clusteraddr) { int clusterno; int index, offset; clusterno = (clusteraddr-trkcache.trkbgnaddr) / trkcache.clustersize; index = clusterno / MASKBYTESZ; offset = clusterno % MASKBYTESZ; if (index < trkcache.dirtymaskcnts) { trkcache.dirty[index] |= (1 << offset); return 0; } else { syslog(LOG_ERR, "Don't know how to handle the cache index"); exit(1); } return (0); } /* *----------------------------------------------------------------------------- * verify_cache() *----------------------------------------------------------------------------- */ int verify_cache(dfs_t * dfs, int clusteraddr, int attrib) { int rcode = 0; int trkstartaddr; int trkendaddr; static int lastop= -1; if (clusteraddr < trkcache.trkbgnaddr || clusteraddr >= trkcache.trkendaddr || (lastop == CACHE_WRITE && attrib == CACHE_READ)) { if (cache_dirty()) if (rcode = cache_writeback(dfs)) return rcode; trkstartaddr = (clusteraddr-dfs->dfs_fileaddr)/trkcache.trksize* trkcache.trksize+dfs->dfs_fileaddr; trkendaddr = trkstartaddr + trkcache.trksize; if (trkendaddr > partendaddr) trkendaddr = partendaddr; if (attrib == CACHE_READ || attrib == CACHE_WRITE) { lseek(dfs->dfs_fd, trkstartaddr, 0); if (read(dfs->dfs_fd, trkcache.bufp, trkendaddr - trkstartaddr) < 0) return errno; } trkcache.trkbgnaddr = trkstartaddr; trkcache.trkendaddr = trkendaddr; lastop = attrib; } return (rcode); } /* *----------------------------------------------------------------------------- * cache_writeback() *----------------------------------------------------------------------------- */ int cache_writeback(dfs_t * dfs) { int remainclusters; int i, j, count, start, end; start = -1; remainclusters = trkcache.clusterspertrk; for (i = 0; i < trkcache.dirtymaskcnts; i++) { count = (remainclusters >= MASKBYTESZ) ? MASKBYTESZ : remainclusters; for (j = 0; j < count; j++) { if (trkcache.dirty[i] & (1 << j)) { if (start == -1) { start = i*MASKBYTESZ+j; end = start; } else end = i*MASKBYTESZ+j; } else { if (start != -1) { if (disk_write(dfs, start, end)) return errno; start = -1; } } } remainclusters -= count; } if (start != -1) if (disk_write(dfs, start, end)) return (errno); for (i = 0; i < trkcache.dirtymaskcnts; i++) trkcache.dirty[i] = 0; return (0); } /* *----------------------------------------------------------------------------- * disk_write() *----------------------------------------------------------------------------- */ int disk_write(dfs_t * dfs, int startcluster, int endcluster) { int clusteraddroffset; int writesize; int wrotesize; clusteraddroffset = startcluster*trkcache.clustersize; writesize = trkcache.clustersize*(endcluster-startcluster+1); lseek(dfs->dfs_fd, trkcache.trkbgnaddr+clusteraddroffset, 0); wrotesize = write(dfs->dfs_fd, &trkcache.bufp[clusteraddroffset],writesize); if (wrotesize < 0) return errno; if (wrotesize != writesize) return (1); return (0); } /* *----------------------------------------------------------------------------- * to_unixname() * This routine takes a (name, ext) tuple and converts it to a sname. *----------------------------------------------------------------------------- */ void to_unixname(char *name, char *ext, char *sname) { int i; int j; for (i = 0; i < 8 && name[i] != ' '; i++) sname[i] = tolower(name[i]); if (strncmp(ext, nullext, 3) == 0) j = 0; else { sname[i++] = '.'; for (j = 0; j < 3 && ext[j] != ' '; j++) sname[i + j] = tolower(ext[j]); } sname[i + j] = '\0'; return; } /* *----------------------------------------------------------------------------- * to_dosname() * This routine takes a sname and converts it into a (name, ext) tuple. *----------------------------------------------------------------------------- */ void to_dosname(char *name, char *ext, char *uname) { u_int ext_len; int i; u_int name_len; char *p; p = strchr(uname, '.'); if (p == NULL) { name_len = strlen(uname); if (name_len > 8) name_len = 8; ext_len = 0; } else { name_len = p - uname; if (name_len > 8) name_len = 8; ext_len = strlen(p + 1); if (ext_len > 3) ext_len = 3; } for (i = 0; i < name_len; i++) name[i] = toupper(uname[i]); for (; i < 8; i++) name[i] = ' '; for (i = 0; i < ext_len; i++) ext[i] = toupper(p[i + 1]); for (; i < 3; i++) ext[i] = ' '; return; } /* *---------------------------------------------------------------------------- * vfat_print11() *---------------------------------------------------------------------------- */ char *vfat_print11(char *sname) { static char dupsname[12]; strncpy(dupsname, sname, MSDOS_NAME); dupsname[11] = '\0'; return (dupsname); } /* *---------------------------------------------------------------------------- * dosname_cmp() * This routine performs a case-insensitive comparison of two 11 char names. * Returns (1): strings identical. * Returns (0): strings non-identical. *---------------------------------------------------------------------------- */ int dosname_cmp(char *s1, char *s2) { int i; char *t1, *t2; char ch1, ch2; for (i = 0, t1 = s1, t2 = s2; i < MSDOS_NAME; i++, t1++, t2++){ if (*t1 >= 'A' && *t1 <= 'Z') ch1 = *t1+32; else ch1 = *t1; if (*t2 >= 'A' && *t2 <= 'Z') ch2 = *t2+32; else ch2 = *t2; if (ch1 != ch2) return (0); } return (1); } /* *----------------------------------------------------------------------------- * dosname_cmp_lname() * This routine performs a case-insensitive comparsion of two names. * The names might be long names or even shortnames. * Returns (1): strings identical. * Returns (0): strings non-identical. *----------------------------------------------------------------------------- */ int dosname_cmp_lname(char *s1, char *s2) { char *t1, *t2; char ch1, ch2; for (t1 = s1, t2 = s2; *t1 != '\0' && *t2 != '\0'; t1++, t2++){ if (*t1 >= 'A' && *t1 <= 'Z') ch1 = *t1+32; else ch1 = *t1; if (*t2 >= 'A' && *t2 <= 'Z') ch2 = *t2+32; else ch2 = *t2; if (ch1 != ch2) return (0); } if (*t1 == '\0' && *t2 == '\0') return (1); return (0); } /* *---------------------------------------------------------------------------- * end_cluster() *---------------------------------------------------------------------------- */ int end_cluster(dfs_t *dfs, u_short cluster) { if (fat_entry_size == 12){ if (cluster > 0x0FF8) return (1); return (0); } else if (fat_entry_size == 16){ if (cluster > 0xFFF8) return (1); return (0); } return (0); }