1
0
Files
irix-657m-src/eoe/cmd/mountdos/dos_util.c
2022-09-29 17:59:04 +03:00

2507 lines
80 KiB
C

/*
*=============================================================================
* 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 <stdio.h>
#include <sys/bsd_types.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syslog.h>
#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);
}