partitionmanager: use fatlabel program from dosfstools to set the label of FAT16 filesystems

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-09-27 19:08:21 +03:00
parent 6aff2cd4fd
commit 40be583e14
45 changed files with 4 additions and 6550 deletions

View file

@ -49,9 +49,7 @@ add_definitions(${KDE4_ENABLE_EXCEPTIONS})
include_directories(
${UUID_INCLUDE_DIRS}
${BLKID_INCLUDE_DIRS}
lib/
src/
)
add_subdirectory(lib)
add_subdirectory(src)

View file

@ -1,19 +0,0 @@
# Copyright (C) 2008 by Volker Lanz <vl@fidra.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
add_subdirectory(fatlabel)

View file

@ -1,49 +0,0 @@
# Copyright (C) 2010 by Volker Lanz <vl@fidra.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -fno-strict-aliasing -fvisibility=hidden")
file(GLOB libfatlabel_SRCS
*.c
)
include_directories(.)
############################################
add_library(libfatlabel SHARED ${libfatlabel_SRCS})
target_link_libraries(libfatlabel)
set_target_properties(libfatlabel PROPERTIES
PREFIX ""
OUTPUT_NAME "libpartitionmanagerfatlabel"
)
install(TARGETS libfatlabel ${INSTALL_TARGETS_DEFAULT_ARGS})
############################################
option(MLABEL_EXECUTABLE "Build a test executable for libfatlabel" OFF)
mark_as_advanced(MLABEL_EXECUTABLE)
if (MLABEL_EXECUTABLE)
set(app_SRCS app/main.c)
add_executable(fatlabel ${app_SRCS})
target_link_libraries(fatlabel libfatlabel)
install(TARGETS fatlabel ${INSTALL_TARGETS_DEFAULT_ARGS})
endif (MLABEL_EXECUTABLE)

View file

@ -1,57 +0,0 @@
/***************************************************************************
* Copyright (C) 2010 by Volker Lanz <vl@fidra.de> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include "fatlabel/fatlabel.h"
#include <stdio.h>
int main(int argc, char **argv)
{
if (argc != 3)
{
fprintf(stderr, "usage: %s <device> <label>\n", argv[0]);
return 1;
}
const char* deviceName = argv[1];
const char* newLabel = argv[2];
int ret = fatlabel_set_label(deviceName, newLabel);
switch(ret)
{
case -1:
fprintf(stderr, "Label too long\n");
break;
case -2:
fprintf(stderr, "%s: Cannot initialize drive\n", argv[0]);
break;
case -3:
fprintf(stderr, "vfat lookup failed\n");
break;
case 0:
default:
break;
}
return ret;
}

View file

@ -1,392 +0,0 @@
/* Copyright 1997,2001-2003 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*
* Buffer read/write module
*/
#include "msdos.h"
#include "mtools.h"
#include "buffer.h"
#include "force_io.h"
#include "stream.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROUND_DOWN(value, grain) ((value) - (value) % (grain))
#define ROUND_UP(value, grain) ROUND_DOWN((value) + (grain)-1, (grain))
struct Buffer_t
{
struct Class_t *Class;
int refs;
struct Stream_t *Next;
struct Stream_t *Buffer;
size_t size; /* size of read/write buffer */
int dirty; /* is the buffer dirty? */
size_t sectorSize; /* sector size: all operations happen in multiples of this */
size_t cylinderSize; /* cylinder size: preferred alignemnt, but for efficiency, less data may be read */
int ever_dirty; /* was the buffer ever dirty? */
size_t dirty_pos;
size_t dirty_end;
off_t current; /* first sector in buffer */
size_t cur_size; /* the current size */
char *buf; /* disk read/write buffer */
};
/*
* Flush a dirty buffer to disk. Resets Buffer->dirty to zero.
* All errors are fatal.
*/
static int _buf_flush(struct Buffer_t *Buffer)
{
if (!Buffer->Next || !Buffer->dirty)
return 0;
if(Buffer->current < 0L)
{
fprintf(stderr,"Should not happen\n");
return -1;
}
int ret = force_write(Buffer->Next, Buffer->buf + Buffer->dirty_pos, Buffer->current + Buffer->dirty_pos, Buffer->dirty_end - Buffer->dirty_pos);
if (ret != (signed int) (Buffer->dirty_end - Buffer->dirty_pos))
{
if (ret < 0)
perror("buffer_flush: write");
else
fprintf(stderr,"buffer_flush: short write\n");
return -1;
}
Buffer->dirty = 0;
Buffer->dirty_end = 0;
Buffer->dirty_pos = 0;
return 0;
}
static int invalidate_buffer(struct Buffer_t *Buffer, off_t start)
{
if(_buf_flush(Buffer) < 0)
return -1;
/* start reading at the beginning of start's sector
* don't start reading too early, or we might not even reach
* start */
Buffer->current = ROUND_DOWN(start, Buffer->sectorSize);
Buffer->cur_size = 0;
return 0;
}
#undef OFFSET
#define OFFSET (start - This->current)
typedef enum position_t
{
OUTSIDE,
APPEND,
INSIDE,
ERROR
} position_t;
static position_t isInBuffer(struct Buffer_t *This, off_t start, size_t *len)
{
if(start >= This->current && start < This->current + (off_t)This->cur_size)
{
maximize(*len, This->cur_size - OFFSET);
return INSIDE;
}
else if(start == This->current + (off_t)This->cur_size && This->cur_size < This->size && *len >= This->sectorSize)
{
/* append to the buffer for this, three conditions have to
* be met:
* 1. The start falls exactly at the end of the currently
* loaded data
* 2. There is still space
* 3. We append at least one sector
*/
maximize(*len, This->size - This->cur_size);
*len = ROUND_DOWN(*len, This->sectorSize);
return APPEND;
}
else
{
if(invalidate_buffer(This, start) < 0)
return ERROR;
maximize(*len, This->cylinderSize - OFFSET);
maximize(*len, This->cylinderSize - This->current % This->cylinderSize);
return OUTSIDE;
}
}
static int buf_read(struct Stream_t *Stream, char *buf, off_t start, size_t len)
{
DeclareThis(struct Buffer_t);
if(!len)
return 0;
switch(isInBuffer(This, start, &len))
{
case OUTSIDE:
case APPEND:
{
/* always load until the end of the cylinder */
size_t length = This->cylinderSize - (This->current + This->cur_size) % This->cylinderSize;
maximize(length, This->size - This->cur_size);
/* read it! */
int ret = READS(This->Next, This->buf + This->cur_size, This->current + This->cur_size, length);
if (ret < 0)
return ret;
This->cur_size += ret;
if (This->current + (off_t)This->cur_size < start)
{
fprintf(stderr, "Short buffer fill\n");
return -1;
}
break;
}
case INSIDE:
/* nothing to do */
break;
case ERROR:
return -1;
}
int offset = OFFSET;
char* disk_ptr = This->buf + offset;
maximize(len, This->cur_size - offset);
memcpy(buf, disk_ptr, len);
return len;
}
static int buf_write(struct Stream_t *Stream, char *buf, off_t start, size_t len)
{
DeclareThis(struct Buffer_t);
size_t offset;
if(!len)
return 0;
This->ever_dirty = 1;
switch(isInBuffer(This, start, &len))
{
case OUTSIDE:
if(start % This->cylinderSize || len < This->sectorSize)
{
size_t readSize;
int ret;
readSize = This->cylinderSize - This->current % This->cylinderSize;
ret = READS(This->Next, This->buf, This->current, readSize);
/* read it! */
if (ret < 0)
return ret;
if(ret % This->sectorSize)
{
fprintf(stderr, "Weird: read size (%d) not a multiple of sector size (%d)\n", ret, (int) This->sectorSize);
ret -= ret % This->sectorSize;
if(ret == 0)
{
fprintf(stderr, "Nothing left\n");
return -1; // TODO: check in caller
}
}
This->cur_size = ret;
/* for dosemu. Autoextend size */
if(!This->cur_size)
{
memset(This->buf,0,readSize);
This->cur_size = readSize;
}
offset = OFFSET;
break;
}
/* FALL THROUGH */
case APPEND:
len = ROUND_DOWN(len, This->sectorSize);
offset = OFFSET;
maximize(len, This->size - offset);
This->cur_size += len;
if(This->Next->Class->pre_allocate)
PRE_ALLOCATE(This->Next,
This->current + This->cur_size);
break;
case INSIDE:
/* nothing to do */
offset = OFFSET;
maximize(len, This->cur_size - offset);
break;
case ERROR:
return -1;
default:
return -1; // TODO: check in caller
}
char* disk_ptr = This->buf + offset;
/* extend if we write beyond end */
if(offset + len > This->cur_size) {
len -= (offset + len) % This->sectorSize;
This->cur_size = len + offset;
}
memcpy(disk_ptr, buf, len);
if(!This->dirty || offset < This->dirty_pos)
This->dirty_pos = ROUND_DOWN(offset, This->sectorSize);
if(!This->dirty || offset + len > This->dirty_end)
This->dirty_end = ROUND_UP(offset + len, This->sectorSize);
if(This->dirty_end > This->cur_size)
{
fprintf(stderr, "Internal error, dirty end too big dirty_end=%x cur_size=%x len=%x offset=%d sectorSize=%x\n",
(unsigned int) This->dirty_end,
(unsigned int) This->cur_size,
(unsigned int) len,
(int) offset, (int) This->sectorSize);
fprintf(stderr, "offset + len + grain - 1 = %x\n", (int) (offset + len + This->sectorSize - 1));
fprintf(stderr, "ROUNDOWN(offset + len + grain - 1) = %x\n", (int)ROUND_DOWN(offset + len + This->sectorSize - 1, This->sectorSize));
fprintf(stderr, "This->dirty = %d\n", This->dirty);
return -1; // TODO: check in caller
}
This->dirty = 1;
return len;
}
static int buf_flush(struct Stream_t *Stream)
{
int ret;
DeclareThis(struct Buffer_t);
if (!This->ever_dirty)
return 0;
ret = _buf_flush(This);
if(ret == 0)
This->ever_dirty = 0;
return ret;
}
static int buf_free(struct Stream_t *Stream)
{
DeclareThis(struct Buffer_t);
if(This->buf)
free(This->buf);
This->buf = 0;
return 0;
}
static struct Class_t BufferClass =
{
buf_read,
buf_write,
buf_flush,
buf_free,
0, /* set_geom */
get_data_pass_through, /* get_data */
0, /* pre-allocate */
get_dosConvert_pass_through /* dos convert */
};
struct Stream_t *buf_init(struct Stream_t *Next, int size, int cylinderSize, int sectorSize)
{
struct Buffer_t *Buffer;
struct Stream_t *Stream;
if(size % cylinderSize != 0)
{
fprintf(stderr, "size not multiple of cylinder size\n");
return NULL; // TODO: check in caller
}
if(cylinderSize % sectorSize != 0)
{
fprintf(stderr, "cylinder size not multiple of sector size\n");
return NULL; // TODO: check in caller
}
if(Next->Buffer)
{
Next->refs--;
Next->Buffer->refs++;
return Next->Buffer;
}
Stream = (struct Stream_t *) malloc (sizeof(struct Buffer_t));
if(!Stream)
return 0;
Buffer = (struct Buffer_t *) Stream;
Buffer->buf = malloc(size);
if (!Buffer->buf)
{
free(Stream);
return 0;
}
Buffer->size = size;
Buffer->dirty = 0;
Buffer->cylinderSize = cylinderSize;
Buffer->sectorSize = sectorSize;
Buffer->ever_dirty = 0;
Buffer->dirty_pos = 0;
Buffer->dirty_end = 0;
Buffer->current = 0L;
Buffer->cur_size = 0; /* buffer currently empty */
Buffer->Next = Next;
Buffer->Class = &BufferClass;
Buffer->refs = 1;
Buffer->Buffer = 0;
Buffer->Next->Buffer = (struct Stream_t *) Buffer;
return Stream;
}

View file

@ -1,26 +0,0 @@
/* Copyright 1996,1997,2001,2002,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_BUFFER_H
#define MTOOLS_BUFFER_H
struct Stream_t;
struct Stream_t *buf_init(struct Stream_t *Next, int size, int cylinderSize, int sectorSize);
#endif

View file

@ -1,325 +0,0 @@
/* Copyright 2008,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*
* Various character set conversions used by mtools
*/
#include "msdos.h"
#include "mtools.h"
#include "file_name.h"
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <iconv.h>
#include <langinfo.h>
#include <string.h>
struct doscp_t
{
iconv_t from;
iconv_t to;
} doscp_t;
static unsigned int mtools_default_codepage = 850;
static const char *wcharCp = NULL;
static const char* wcharTries[] =
{
"WCHAR_T",
"UTF-32BE", "UTF-32LE",
"UTF-16BE", "UTF-16LE",
"UTF-32", "UTF-16",
"UCS-4BE", "UCS-4LE",
"UCS-2BE", "UCS-2LE",
"UCS-4", "UCS-2"
};
static const wchar_t *testString = L"ab";
static int tryConvert(const char *testCp)
{
char *inbuf = (char *)testString;
size_t inbufLen = 2*sizeof(wchar_t);
char outbuf[3];
char *outbufP = outbuf;
size_t outbufLen = 2*sizeof(char);
iconv_t test = iconv_open("ASCII", testCp);
if(test == (iconv_t) -1)
goto fail0;
size_t res = iconv(test, &inbuf, &inbufLen, &outbufP, &outbufLen);
if(res != 0 || outbufLen != 0 || inbufLen != 0)
goto fail;
if(memcmp(outbuf, "ab", 2))
goto fail;
return 1;
fail:
iconv_close(test);
fail0:
return 0;
}
static const char *getWcharCp()
{
if(wcharCp != NULL)
return wcharCp;
unsigned int i;
for(i = 0; i < sizeof(wcharTries) / sizeof(wcharTries[0]); i++)
if(tryConvert(wcharTries[i]))
return wcharCp = wcharTries[i];
fprintf(stderr, "No codepage found for wchar_t\n");
return NULL;
}
struct doscp_t *cp_open(int codepage)
{
char dosCp[17];
if(codepage == 0)
codepage = mtools_default_codepage;
if(codepage < 0 || codepage > 9999)
{
fprintf(stderr, "Bad codepage %d\n", codepage);
return NULL;
}
if(getWcharCp() == NULL)
return NULL;
sprintf(dosCp, "CP%d", codepage);
iconv_t *from = iconv_open(wcharCp, dosCp);
if(from == (iconv_t)-1)
{
fprintf(stderr, "Error converting to codepage %d %s\n", codepage, strerror(errno));
return NULL;
}
sprintf(dosCp, "CP%d//TRANSLIT", codepage);
iconv_t *to = iconv_open(dosCp, wcharCp);
if(to == (iconv_t)-1)
{
/* Transliteration not supported? */
sprintf(dosCp, "CP%d", codepage);
to = iconv_open(dosCp, wcharCp);
}
if(to == (iconv_t)-1)
{
iconv_close(from);
fprintf(stderr, "Error converting to codepage %d %s\n", codepage, strerror(errno));
return NULL;
}
struct doscp_t *ret = New(struct doscp_t);
if(ret == NULL)
return ret;
ret->from = from;
ret->to = to;
return ret;
}
void cp_close(struct doscp_t *cp)
{
iconv_close(cp->to);
iconv_close(cp->from);
free(cp);
}
int dos_to_wchar(struct doscp_t *cp, char *dos, wchar_t *wchar, size_t len)
{
size_t in_len = len;
size_t out_len = len*sizeof(wchar_t);
wchar_t *dptr = wchar;
int r = iconv(cp->from, &dos, &in_len, (char **)&dptr, &out_len);
if(r < 0)
return r;
*dptr = L'\0';
return dptr - wchar;
}
/**
* Converts len wide character to destination. Caller's responsibility to
* ensure that dest is large enough.
* mangled will be set if there has been an untranslatable character.
*/
static int safe_iconv(iconv_t conv, const wchar_t *wchar, char *dest, size_t len, int *mangled)
{
size_t in_len = len * sizeof(wchar_t);
size_t out_len = len * 4;
char *dptr = dest;
while (in_len > 0)
{
int r = iconv(conv, (char**)&wchar, &in_len, &dptr, &out_len);
/* everything transformed, or error that is _not_ a bad character */
if(r >= 0 || errno != EILSEQ)
break;
*mangled |= 1;
if(dptr)
*dptr++ = '_';
in_len--;
wchar++;
out_len--;
}
len = dptr-dest; /* how many dest characters have there been generated */
/* eliminate question marks which might have been formed by
untransliterable characters */
unsigned int i;
for (i = 0; i < len; i++)
{
if (dest[i] == '?')
{
dest[i] = '_';
*mangled |= 1;
}
}
return len;
}
void wchar_to_dos(struct doscp_t *cp, wchar_t *wchar, char *dos, size_t len, int *mangled)
{
safe_iconv(cp->to, wchar, dos, len, mangled);
}
static iconv_t to_native = NULL;
static int initialize_to_native(void)
{
if(to_native != NULL)
return 0;
char *li = nl_langinfo(CODESET);
int len = strlen(li) + 11;
if(getWcharCp() == NULL)
return -1; // TODO: make caller check return code
char *cp = malloc(len);
strcpy(cp, li);
strcat(cp, "//TRANSLIT");
to_native = iconv_open(cp, wcharCp);
if(to_native == (iconv_t) -1)
to_native = iconv_open(li, wcharCp);
if(to_native == (iconv_t) -1)
fprintf(stderr, "Could not allocate iconv for %s\n", cp);
free(cp);
if(to_native == (iconv_t) -1)
return -1;
return 0;
}
/**
* Convert wchar string to native, converting at most len wchar characters
* Returns number of generated native characters
*/
int wchar_to_native(const wchar_t *wchar, char *native, size_t len)
{
int mangled;
initialize_to_native();
len = wcsnlen(wchar,len);
int r = safe_iconv(to_native, wchar, native, len, &mangled);
native[r] = '\0';
return r;
}
/**
* Convert native string to wchar string, converting at most len wchar
* characters. If end is supplied, stop conversion when source pointer
* exceeds end. Returns number of converted wchars
*/
int native_to_wchar(const char *native, wchar_t *wchar, size_t len, const char *end, int *mangled)
{
mbstate_t ps;
memset(&ps, 0, sizeof(ps));
unsigned int i;
for(i = 0; i < len && (native < end || !end); i++)
{
int r = mbrtowc(wchar+i, native, len, &ps);
if(r < 0)
{
/* Unconvertible character. Just pretend it's Latin1
encoded (if valid Latin1 character) or substitue
with an underscore if not
*/
char c = *native;
if(c >= '\xa0' && c < '\xff')
wchar[i] = c & 0xff;
else
wchar[i] = '_';
memset(&ps, 0, sizeof(ps));
r = 1;
}
if(r == 0)
break;
native += r;
}
if(mangled && end && native < end)
*mangled |= 3;
wchar[i]='\0';
return (int)i;
}

View file

@ -1,31 +0,0 @@
/* Copyright 1986-1992 Emmet P. Gray.
* Copyright 1996-2003,2006,2007,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mtools.h"
#include "devices.h"
int init_geom(int UNUSED(fd), struct device *dev, struct device *orig_dev, struct stat64 UNUSED(*statbuf))
{
if(!orig_dev || !orig_dev->tracks || !dev || !dev->tracks)
return 0; /* no original device. This is ok */
return(orig_dev->tracks != dev->tracks ||
orig_dev->heads != dev->heads ||
orig_dev->sectors != dev->sectors);
}

View file

@ -1,51 +0,0 @@
/* Copyright 1996-2005,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_DEVICES_H
#define MTOOLS_DEVICES_H
#include <sys/types.h>
#include <sys/stat.h>
struct device
{
const char *name; /* full path to device */
int fat_bits; /* FAT encoding scheme */
unsigned int mode; /* any special open() flags */
unsigned int tracks; /* tracks */
unsigned int heads; /* heads */
unsigned int sectors; /* sectors */
unsigned int hidden; /* number of hidden sectors. Used for mformatting partitioned devices */
off_t offset; /* skip this many bytes */
unsigned int partition;
unsigned int misc_flags;
/* Linux only stuff */
unsigned int ssize;
unsigned int use_2m;
/* internal variables */
int file_nr; /* used during parsing */
unsigned int blocksize; /* size of disk block in bytes */
int codepage; /* codepage for shortname encoding */
const char *cfg_filename; /* used for debugging purposes */
};
int init_geom(int fd, struct device *dev, struct device *orig_dev, struct stat64 *statbuf);
#endif

View file

@ -1,335 +0,0 @@
/* Copyright 1998,2001-2003,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "vfat.h"
#include "dirCache.h"
#include "file.h"
#include "mtools.h"
#include <wctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BITS_PER_INT (sizeof(unsigned int) * 8)
static unsigned int rol(unsigned int arg, int shift)
{
arg &= 0xffffffff; /* for 64 bit machines */
return (arg << shift) | (arg >> (32 - shift));
}
static int calcHash(wchar_t *name)
{
unsigned long hash = 0;
int i = 0;
while(*name)
{
/* rotate it */
hash = rol(hash,5); /* a shift of 5 makes sure we spread quickly
* over the whole width, moreover, 5 is
* prime with 32, which makes sure that
* successive letters cannot cover each
* other easily */
wchar_t c = towupper(*name);
hash ^= (c * (c+2)) ^ (i * (i+2));
hash &= 0xffffffff;
i++;
name++;
}
hash = hash * (hash + 2);
/* the following two xors make sure all info is spread evenly over all
* bytes. Important if we only keep the low order bits later on */
hash ^= (hash & 0xfff) << 12;
hash ^= (hash & 0xff000) << 24;
return hash;
}
static int addBit(unsigned int *bitmap, int hash, int checkOnly)
{
int bit = 1 << (hash % BITS_PER_INT);
int entry = (hash / BITS_PER_INT) % DC_BITMAP_SIZE;
if(checkOnly)
return bitmap[entry] & bit;
bitmap[entry] |= bit;
return 1;
}
static int _addHash(struct dirCache_t *cache, unsigned int hash, int checkOnly)
{
return
addBit(cache->bm0, hash, checkOnly) &&
addBit(cache->bm1, rol(hash,12), checkOnly) &&
addBit(cache->bm2, rol(hash,24), checkOnly);
}
static void addNameToHash(struct dirCache_t *cache, wchar_t *name)
{
_addHash(cache, calcHash(name), 0);
}
static void hashDce(struct dirCache_t *cache, struct dirCacheEntry_t *dce)
{
if(dce->beginSlot != cache->nrHashed)
return;
cache->nrHashed = dce->endSlot;
if(dce->longName)
addNameToHash(cache, dce->longName);
addNameToHash(cache, dce->shortName);
}
int isHashed(struct dirCache_t *cache, wchar_t *name)
{
return _addHash(cache, calcHash(name), 1);
}
int growDirCache(struct dirCache_t *cache, int slot)
{
if(slot < 0)
{
fprintf(stderr, "Bad slot %d\n", slot);
return -1; // TODO: check in caller
}
if( cache->nr_entries <= slot)
{
cache->entries = realloc(cache->entries, (slot+1) * 2 * sizeof(struct dirCacheEntry_t *));
if(!cache->entries)
return -1;
for (int i = cache->nr_entries; i < (slot+1) * 2; i++)
cache->entries[i] = 0;
cache->nr_entries = (slot+1) * 2;
}
return 0;
}
struct dirCache_t *allocDirCache(struct Stream_t *Stream, int slot)
{
if(slot < 0)
{
fprintf(stderr, "Bad slot %d\n", slot);
return NULL;
}
struct dirCache_t **dcp = getDirCacheP(Stream);
if(!*dcp)
{
*dcp = New(struct dirCache_t);
if(!*dcp)
return 0;
(*dcp)->entries = NewArray((slot+1)*2+5, struct dirCacheEntry_t *);
if(!(*dcp)->entries)
{
free(*dcp);
return 0;
}
(*dcp)->nr_entries = (slot+1) * 2;
memset( (*dcp)->bm0, 0, DC_BITMAP_SIZE);
memset( (*dcp)->bm1, 0, DC_BITMAP_SIZE);
memset( (*dcp)->bm2, 0, DC_BITMAP_SIZE);
(*dcp)->nrHashed = 0;
}
else if(growDirCache(*dcp, slot) < 0)
return 0;
return *dcp;
}
static int freeDirCacheRange(struct dirCache_t *cache, unsigned int beginSlot, unsigned int endSlot)
{
if(endSlot < beginSlot)
{
fprintf(stderr, "Bad slots %d %d in free range\n", beginSlot, endSlot);
return -1; // TODO: check in caller
}
while(beginSlot < endSlot)
{
struct dirCacheEntry_t *entry = cache->entries[beginSlot];
if(!entry)
{
beginSlot++;
continue;
}
unsigned int clearEnd = entry->endSlot;
if(clearEnd > endSlot)
clearEnd = endSlot;
unsigned int clearBegin = beginSlot;
for(unsigned int i = clearBegin; i <clearEnd; i++)
cache->entries[i] = 0;
if(entry->endSlot == endSlot)
entry->endSlot = beginSlot;
else if(entry->beginSlot == beginSlot)
entry->beginSlot = endSlot;
else
{
fprintf(stderr, "Internal error, non contiguous de-allocation\n");
fprintf(stderr, "%d %d\n", beginSlot, endSlot);
fprintf(stderr, "%d %d\n", entry->beginSlot, entry->endSlot);
return -1; // TODO: check in caller
}
if(entry->beginSlot == entry->endSlot)
{
if(entry->longName)
free(entry->longName);
if(entry->shortName)
free(entry->shortName);
free(entry);
}
beginSlot = clearEnd;
}
return 0;
}
static struct dirCacheEntry_t *allocDirCacheEntry(struct dirCache_t *cache, int beginSlot, int endSlot, dirCacheEntryType_t type)
{
if(growDirCache(cache, endSlot) < 0)
return 0;
struct dirCacheEntry_t *entry = New(struct dirCacheEntry_t);
if(!entry)
return 0;
entry->type = type;
entry->longName = 0;
entry->shortName = 0;
entry->beginSlot = beginSlot;
entry->endSlot = endSlot;
freeDirCacheRange(cache, beginSlot, endSlot);
for(int i = beginSlot; i<endSlot; i++)
cache->entries[i] = entry;
return entry;
}
struct dirCacheEntry_t *addUsedEntry(struct dirCache_t *cache, int beginSlot, int endSlot, wchar_t *longName, wchar_t *shortName, struct directory *dir)
{
if(endSlot < beginSlot)
{
fprintf(stderr,"Bad slots %d %d in add used entry\n", beginSlot, endSlot);
return NULL;
}
struct dirCacheEntry_t *entry = allocDirCacheEntry(cache, beginSlot, endSlot, DCET_USED);
if(!entry)
return 0;
entry->beginSlot = beginSlot;
entry->endSlot = endSlot;
if(longName)
entry->longName = wcsdup(longName);
entry->shortName = wcsdup(shortName);
entry->dir = *dir;
hashDce(cache, entry);
return entry;
}
static void mergeFreeSlots(struct dirCache_t *cache, int slot)
{
if(slot == 0)
return;
struct dirCacheEntry_t *previous = cache->entries[slot-1];
struct dirCacheEntry_t *next = cache->entries[slot];
if(next && next->type == DCET_FREE && previous && previous->type == DCET_FREE)
{
for(unsigned int i = next->beginSlot; i < next->endSlot; i++)
cache->entries[i] = previous;
previous->endSlot = next->endSlot;
free(next);
}
}
struct dirCacheEntry_t *addFreeEntry(struct dirCache_t *cache, unsigned int beginSlot, unsigned int endSlot)
{
if(beginSlot < cache->nrHashed)
cache->nrHashed = beginSlot;
if(endSlot < beginSlot)
{
fprintf(stderr, "Bad slots %d %d in add free entry\n", beginSlot, endSlot);
return NULL;
}
if(endSlot == beginSlot)
return 0;
allocDirCacheEntry(cache, beginSlot, endSlot, DCET_FREE);
mergeFreeSlots(cache, beginSlot);
mergeFreeSlots(cache, endSlot);
return cache->entries[beginSlot];
}
struct dirCacheEntry_t *addEndEntry(struct dirCache_t *cache, int pos)
{
return allocDirCacheEntry(cache, pos, pos+1, DCET_END);
}
void freeDirCache(struct Stream_t *Stream)
{
struct dirCache_t **dcp = getDirCacheP(Stream);
struct dirCache_t *cache = *dcp;
if(cache)
{
freeDirCacheRange(cache, 0, cache->nr_entries);
free(cache);
*dcp = 0;
}
}

View file

@ -1,60 +0,0 @@
/* Copyright 1997,1999,2001-2003,2008,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_DIRCACHE_H
#define MTOOLS_DIRCACHE_H
#include "directory.h"
#include <wchar.h>
typedef enum {
DCET_FREE,
DCET_USED,
DCET_END
} dirCacheEntryType_t;
#define DC_BITMAP_SIZE 128
struct dirCacheEntry_t {
dirCacheEntryType_t type;
unsigned int beginSlot;
unsigned int endSlot;
wchar_t *shortName;
wchar_t *longName;
struct directory dir;
};
struct dirCache_t {
struct dirCacheEntry_t **entries;
int nr_entries;
unsigned int nrHashed;
unsigned int bm0[DC_BITMAP_SIZE];
unsigned int bm1[DC_BITMAP_SIZE];
unsigned int bm2[DC_BITMAP_SIZE];
};
int isHashed(struct dirCache_t *cache, wchar_t *name);
int growDirCache(struct dirCache_t *cache, int slot);
struct dirCache_t *allocDirCache(struct Stream_t *Stream, int slot);
struct dirCacheEntry_t *addUsedEntry(struct dirCache_t *Stream, int begin, int end, wchar_t *longName, wchar_t *shortName, struct directory *dir);
void freeDirCache(struct Stream_t *Stream);
struct dirCacheEntry_t *addFreeEntry(struct dirCache_t *Stream, unsigned int begin, unsigned int end);
struct dirCacheEntry_t *addEndEntry(struct dirCache_t *Stream, int pos);
#endif

View file

@ -1,380 +0,0 @@
/* Copyright 1995 David C. Niemi
* Copyright 1996-2002,2008,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "directory.h"
#include "msdos.h"
#include "stream.h"
#include "mtools.h"
#include "file.h"
#include "fs.h"
#include "file_name.h"
#include "fat.h"
#include "init.h"
#include "force_io.h"
#include "buffer.h"
#include "nameclash.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
static const char* short_illegals = ";+=[]',\"*\\<>/?:|";
static const char* long_illegals = "\"*\\<>/?:|\005";
/*
* Read a directory entry into caller supplied buffer
*/
struct directory *dir_read(struct direntry_t *entry, int *error)
{
int n;
*error = 0;
if((n=force_read(entry->Dir, (char *) (&entry->dir),
(off_t) entry->entry * MDIR_SIZE,
MDIR_SIZE)) != MDIR_SIZE) {
if (n < 0) {
*error = -1;
}
return NULL;
}
return &entry->dir;
}
/*
* Make a subdirectory grow in length. Only subdirectories (not root)
* may grow. Returns a 0 on success, 1 on failure (disk full), or -1
* on error.
*/
int dir_grow(struct Stream_t *Dir, int size)
{
struct Stream_t *Stream = GetFs(Dir);
DeclareThis(struct FsPublic_t);
int ret;
int buflen;
char *buffer;
if (!getfreeMinClusters(Dir, 1))
return -1;
buflen = This->cluster_size * This->sector_size;
if(! (buffer=malloc(buflen)) ){
perror("dir_grow: malloc");
return -1;
}
memset((char *) buffer, '\0', buflen);
ret = force_write(Dir, buffer, (off_t) size * MDIR_SIZE, buflen);
free(buffer);
if(ret < buflen)
return -1;
return 0;
}
void low_level_dir_write(struct direntry_t *entry)
{
force_write(entry->Dir,
(char *) (&entry->dir),
(off_t) entry->entry * MDIR_SIZE, MDIR_SIZE);
}
/*
* Make a directory entry. Builds a directory entry based on the
* name, attribute, starting cluster number, and size. Returns a pointer
* to a static directory structure.
*/
struct directory *mk_entry(const struct dos_name_t *dn, char attr,
unsigned int fat, size_t size, time_t date,
struct directory *ndir)
{
struct tm *now;
time_t date2 = date;
unsigned char hour, min_hi, min_low, sec;
unsigned char year, month_hi, month_low, day;
now = localtime(&date2);
dosnameToDirentry(dn, ndir);
ndir->attr = attr;
ndir->ctime_ms = 0;
hour = now->tm_hour << 3;
min_hi = now->tm_min >> 3;
min_low = now->tm_min << 5;
sec = now->tm_sec / 2;
ndir->ctime[1] = ndir->time[1] = hour + min_hi;
ndir->ctime[0] = ndir->time[0] = min_low + sec;
year = (now->tm_year - 80) << 1;
month_hi = (now->tm_mon + 1) >> 3;
month_low = (now->tm_mon + 1) << 5;
day = now->tm_mday;
ndir -> adate[1] = ndir->cdate[1] = ndir->date[1] = year + month_hi;
ndir -> adate[0] = ndir->cdate[0] = ndir->date[0] = month_low + day;
set_word(ndir->start, fat & 0xffff);
set_word(ndir->startHi, fat >> 16);
set_dword(ndir->size, size);
return ndir;
}
/*
* Make a directory entry from base name. This is supposed to be used
* from places such as mmd for making special entries (".", "..", "/", ...)
* Thus it doesn't bother with character set conversions
*/
struct directory *mk_entry_from_base(const char *base, char attr,
unsigned int fat, size_t size, time_t date,
struct directory *ndir)
{
struct dos_name_t dn;
strncpy(dn.base, base, 8);
strncpy(dn.ext, " ", 3);
return mk_entry(&dn, attr, fat, size, date, ndir);
}
void bufferize(struct Stream_t **Dir)
{
struct Stream_t *BDir;
if(!*Dir)
return;
BDir = buf_init(*Dir, 64*16384, 512, MDIR_SIZE);
if(!BDir)
{
free_stream(Dir);
*Dir = NULL;
}
else
*Dir = BDir;
}
void initializeDirentry(struct direntry_t *entry, struct Stream_t *Dir)
{
entry->entry = -1;
entry->Dir = Dir;
entry->beginSlot = 0;
entry->endSlot = 0;
}
int isNotFound(struct direntry_t *entry)
{
return entry->entry == -2;
}
static int isSpecial(const char *name)
{
return name && (name[0] == '\0' || !strcmp(name, ".") || !strcmp(name, "..")) ? 1 : 0;
}
static int convert_to_shortname(struct doscp_t *cp, struct ClashHandling_t *ch, const char *un, struct dos_name_t *dn)
{
int mangled;
/* Then do conversion to dn */
ch->name_converter(cp, un, &mangled, dn);
dn->sentinel = '\0';
return mangled;
}
static int contains_illegals(const char *string, const char *illegals, int len)
{
for (; *string && len--; string++)
if ((*string < ' ' && *string != '\005' && !(*string & 0x80)) || strchr(illegals, *string))
return 1;
return 0;
}
static int is_reserved(char *ans, int islong)
{
unsigned int i;
static const char *dev3[] = {"CON", "AUX", "PRN", "NUL", " "};
static const char *dev4[] = {"COM", "LPT" };
for (i = 0; i < sizeof(dev3) / sizeof(*dev3); i++)
if (!strncasecmp(ans, dev3[i], 3) && ((islong && !ans[3]) || (!islong && !strncmp(ans + 3, " ", 5))))
return 1;
for (i = 0; i < sizeof(dev4)/sizeof(*dev4); i++)
if (!strncasecmp(ans, dev4[i], 3) && (ans[3] >= '1' && ans[3] <= '4') && ((islong && !ans[4])
|| (!islong && !strncmp(ans + 4, " ", 4))))
return 1;
return 0;
}
static clash_action get_slots(struct Stream_t *Dir,
struct dos_name_t *dosname,
char *longname,
struct scan_state *ssp,
struct ClashHandling_t *ch)
{
struct direntry_t entry;
int pessimisticShortRename = 0;
entry.Dir = Dir;
if ((is_reserved(longname, 1)) || longname[strspn(longname, ". ")] == '\0'
|| contains_illegals(longname, long_illegals, 1024)
|| is_reserved(dosname->base, 0)
|| contains_illegals(dosname->base, short_illegals, 11))
{
return NAMEMATCH_ERROR;
}
else
{
switch (lookupForInsert(Dir,
&entry,
dosname, longname, ssp,
ch->ignore_entry,
ch->source_entry,
pessimisticShortRename &&
ch->use_longname,
ch->use_longname)) {
case -1:
return NAMEMATCH_ERROR;
case 0: /* Single-file error error or skip request */
return NAMEMATCH_SKIP;
case 5: /* Grew directory, try again */
return NAMEMATCH_GREW;
case 6:
return NAMEMATCH_SUCCESS; /* Success */
}
}
return NAMEMATCH_ERROR;
}
static int write_slots(struct Stream_t *Dir, struct dos_name_t *dosname, char *longname, struct scan_state *ssp, write_data_callback *cb, int Case)
{
/* write the file */
if (fat_error(Dir))
return -1;
struct direntry_t entry;
entry.Dir = Dir;
entry.entry = ssp->slot;
native_to_wchar(longname, entry.name, MAX_VNAMELEN, 0, 0);
entry.name[MAX_VNAMELEN] = '\0';
entry.dir.Case = Case & (EXTCASE | BASECASE);
if (cb(dosname, &entry) < 0)
return -2;
if ((ssp->size_needed > 1) && (ssp->free_end - ssp->free_start >= ssp->size_needed))
ssp->slot = write_vfat(Dir, dosname, longname, ssp->free_start, &entry);
else
{
ssp->size_needed = 1;
write_vfat(Dir, dosname, 0, ssp->free_start, &entry);
}
return 0; /* Successfully wrote the file */
}
int mwrite_one(struct Stream_t *Dir, const char *argname, write_data_callback *cb, struct ClashHandling_t *ch)
{
if (argname == NULL)
return -1;
if (isSpecial(argname))
{
fprintf(stderr, "Cannot create entry named . or ..\n");
return -1;
}
/* Copy original argument dstname to working value longname */
char longname[VBUFSIZE];
strncpy(longname, argname, VBUFSIZE - 1);
struct doscp_t *cp = GET_DOSCONVERT(Dir);
struct dos_name_t dosname;
ch->use_longname = convert_to_shortname(cp, ch, longname, &dosname);
ch->action[0] = ch->namematch_default[0];
ch->action[1] = ch->namematch_default[1];
int expanded = 0;
clash_action ret;
for (;;)
{
struct scan_state scan;
switch((ret = get_slots(Dir, &dosname, longname, &scan, ch)))
{
case NAMEMATCH_ERROR:
case NAMEMATCH_SKIP:
return -1;
case NAMEMATCH_GREW:
/* No collision, and not enough slots. Try to grow the directory */
if (expanded)
{
/* Already tried this once, no good */
fprintf(stderr, "No directory slots\n");
return -1;
}
expanded = 1;
if (dir_grow(Dir, scan.max_entry))
return -1;
continue;
case NAMEMATCH_SUCCESS:
return write_slots(Dir, &dosname, longname, &scan, cb, ch->use_longname);
default:
fprintf(stderr, "Internal error: clash_action=%d\n", ret);
return -1;
}
}
return ret;
}
void init_clash_handling(struct ClashHandling_t *ch)
{
ch->ignore_entry = -1;
ch->source_entry = -2;
ch->nowarn = 0; /*Don't ask, just do default action if name collision */
ch->namematch_default[0] = NAMEMATCH_SKIP;
ch->namematch_default[1] = NAMEMATCH_NONE;
ch->name_converter = NULL;
ch->source = -2;
}
void dosnameToDirentry(const struct dos_name_t *dn, struct directory *dir)
{
strncpy(dir->name, dn->base, 8);
strncpy(dir->ext, dn->ext, 3);
}

View file

@ -1,82 +0,0 @@
/* Copyright 1996-2005,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_DIRECTORY_H
#define MTOOLS_DIRECTORY_H
#include "vfat.h"
#include <time.h>
#include <stddef.h>
struct dos_name_t;
struct Stream_t;
struct scan_state;
struct ClashHandling_t;
struct directory
{
char name[8]; /* 0 file name */
char ext[3]; /* 8 file extension */
unsigned char attr; /* 11 attribute byte */
unsigned char Case; /* 12 case of short filename */
unsigned char ctime_ms; /* 13 creation time, milliseconds (?) */
unsigned char ctime[2]; /* 14 creation time */
unsigned char cdate[2]; /* 16 creation date */
unsigned char adate[2]; /* 18 last access date */
unsigned char startHi[2]; /* 20 start cluster, Hi */
unsigned char time[2]; /* 22 time stamp */
unsigned char date[2]; /* 24 date stamp */
unsigned char start[2]; /* 26 starting cluster number */
unsigned char size[4]; /* 28 size of the file */
};
struct direntry_t
{
struct Stream_t *Dir;
int entry; /* slot in parent directory (-3 if root) */
struct directory dir; /* descriptor in parent directory (random if root)*/
wchar_t name[MAX_VNAMELEN + 1]; /* name in its parent directory, or NULL if root */
int beginSlot; /* begin and end slot, for delete */
int endSlot;
};
struct directory *mk_entry(const struct dos_name_t *filename, char attr, unsigned int fat, size_t size, time_t date, struct directory *ndir);
struct directory *mk_entry_from_base(const char *base, char attr, unsigned int fat, size_t size, time_t date, struct directory *ndir);
int dir_grow(struct Stream_t *Dir, int size);
void bufferize(struct Stream_t **Dir);
struct directory *dir_read(struct direntry_t *entry, int *error);
void initializeDirentry(struct direntry_t *entry, struct Stream_t *Dir);
int isNotFound(struct direntry_t *entry);
void low_level_dir_write(struct direntry_t *entry);
void dosnameToDirentry(const struct dos_name_t *n, struct directory *dir);
int lookupForInsert(struct Stream_t *Dir, struct direntry_t *direntry, struct dos_name_t *dosname, char *longname, struct scan_state *ssp, int ignore_entry, int source_entry, int pessimisticShortRename, int use_longname);
typedef int (write_data_callback)(struct dos_name_t*, struct direntry_t*);
void init_clash_handling(struct ClashHandling_t *ch);
int mwrite_one(struct Stream_t *Dir, const char *argname, write_data_callback *cb, struct ClashHandling_t *ch);
#endif

View file

@ -1,796 +0,0 @@
/* Copyright 1996-2006,2008,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "msdos.h"
#include "stream.h"
#include "mtools.h"
#include "fs.h"
#include "file_name.h"
#include "init.h"
#include "force_io.h"
#include "llong.h"
#include "directory.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef long long fatBitMask;
struct FatMap_t {
unsigned char *data;
fatBitMask dirty;
fatBitMask valid;
};
#define SECT_PER_ENTRY (sizeof(fatBitMask)*8)
#define ONE ((fatBitMask) 1)
static int readSector(struct Fs_t *This, char *buf, unsigned int off, size_t size)
{
return READS(This->Next, buf, sectorsToBytes((struct Stream_t *)This, off), size << This->sectorShift);
}
static int forceReadSector(struct Fs_t *This, char *buf, unsigned int off, size_t size)
{
return force_read(This->Next, buf, sectorsToBytes((struct Stream_t *)This, off), size << This->sectorShift);
}
static int forceWriteSector(struct Fs_t *This, char *buf, unsigned int off,
size_t size)
{
return force_write(This->Next, buf, sectorsToBytes((struct Stream_t*)This, off), size << This->sectorShift);
}
static struct FatMap_t *GetFatMap(struct Fs_t *Stream)
{
Stream->fat_error = 0;
int nr_entries = (Stream->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY;
struct FatMap_t *map = NewArray(nr_entries, struct FatMap_t);
if(!map)
return NULL;
int i;
for(i=0; i< nr_entries; i++)
{
map[i].data = 0;
map[i].valid = 0;
map[i].dirty = 0;
}
return map;
}
static int locate(struct Fs_t *Stream, size_t offset, int *slot, int *bit)
{
if(offset >= Stream->fat_len)
return -1;
*slot = offset / SECT_PER_ENTRY;
*bit = offset % SECT_PER_ENTRY;
return 0;
}
static int fatReadSector(struct Fs_t *This, int sector, int slot, int bit, int dupe, fatBitMask bitmap)
{
dupe = (dupe + This->primaryFat) % This->num_fat;
int fat_start = This->fat_start + This->fat_len * dupe;
int nr_sectors = (bitmap == 0) ? SECT_PER_ENTRY - bit % SECT_PER_ENTRY : 1;
/* first, read as much as the buffer can give us */
int ret = readSector(This, (char *)(This->FatMap[slot].data+(bit<<This->sectorShift)), fat_start+sector, nr_sectors);
if(ret < 0)
return 0;
if((unsigned int) ret < This->sector_size)
{
/* if we got less than one sector's worth, insist to get at
* least one sector */
ret = forceReadSector(This, (char*) (This->FatMap[slot].data + (bit << This->sectorShift)), fat_start+sector, 1);
if(ret < (int) This->sector_size)
return 0;
return 1;
}
return ret >> This->sectorShift;
}
static int fatWriteSector(struct Fs_t *This, int sector, int slot, int bit, int dupe)
{
dupe = (dupe + This->primaryFat) % This->num_fat;
if (dupe && !This->writeAllFats)
return This->sector_size;
int fat_start = This->fat_start + This->fat_len * dupe;
return forceWriteSector(This, (char*) (This->FatMap[slot].data + bit * This->sector_size), fat_start + sector, 1);
}
static unsigned char *loadSector(struct Fs_t *This, unsigned int sector, fatAccessMode_t mode, int recurs)
{
int slot;
int bit;
if(locate(This,sector, &slot, &bit) < 0)
return 0;
if(!This->FatMap[slot].data)
{
/* allocate the storage space */
This->FatMap[slot].data = malloc(This->sector_size * SECT_PER_ENTRY);
if(!This->FatMap[slot].data)
return 0;
memset(This->FatMap[slot].data, 0xee, This->sector_size * SECT_PER_ENTRY);
}
if(! (This->FatMap[slot].valid & (ONE << bit)))
{
unsigned int i;
int ret = -1;
for(i=0; i< This->num_fat; i++)
{
/* read the sector */
ret = fatReadSector(This, sector, slot, bit, i,
This->FatMap[slot].valid);
if(ret == 0)
{
fprintf(stderr, "Error reading fat number %d\n", i);
continue;
}
if(This->FatMap[slot].valid)
/* Set recurs if there have already been
* sectors loaded in this bitmap long
*/
recurs = 1;
break;
}
/* all copies bad. Return error */
if (ret == 0)
return 0;
for (i=0; (int) i < ret; i++)
This->FatMap[slot].valid |= ONE << (bit + i);
if(!recurs && ret == 1)
/* do some prefetching, if we happened to only
* get one sector */
loadSector(This, sector+1, mode, 1);
}
if(mode == FAT_ACCESS_WRITE)
{
This->FatMap[slot].dirty |= ONE << bit;
This->fat_dirty = 1;
}
return This->FatMap[slot].data + (bit << This->sectorShift);
}
static unsigned char *getAddress(struct Fs_t *Stream, unsigned int num, fatAccessMode_t mode)
{
int sector = num >> Stream->sectorShift;
unsigned char *ret = 0;
if(sector == Stream->lastFatSectorNr && Stream->lastFatAccessMode >= mode)
ret = Stream->lastFatSectorData;
if(!ret)
{
ret = loadSector(Stream, sector, mode, 0);
if(!ret)
return 0;
Stream->lastFatSectorNr = sector;
Stream->lastFatSectorData = ret;
Stream->lastFatAccessMode = mode;
}
return ret + (num & Stream->sectorMask);
}
static int readByte(struct Fs_t *Stream, int start)
{
unsigned char *address = getAddress(Stream, start, FAT_ACCESS_READ);
return address ? *address : -1;
}
/*
* Fat 12 encoding:
* | byte n | byte n+1 | byte n+2 |
* |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
* | | | | | | | | | | | | | | | | | | | | | | | | |
* | n+0.0 | n+0.5 | n+1.0 | n+1.5 | n+2.0 | n+2.5 |
* \_____ \____ \______/________/_____ /
* ____\______\________/ _____/ ____\_/
* / \ \ / / \
* | n+1.5 | n+0.0 | n+0.5 | n+2.0 | n+2.5 | n+1.0 |
* | FAT entry k | FAT entry k+1 |
*/
/*
* Get and decode a FAT (file allocation table) entry. Returns the cluster
* number on success or 1 on failure.
*/
static unsigned int fat12_decode(struct Fs_t *Stream, unsigned int num)
{
unsigned int start = num * 3 / 2;
int byte0 = readByte(Stream, start);
int byte1 = readByte(Stream, start+1);
if (num < 2 || byte0 < 0 || byte1 < 0 || num > Stream->num_clus+1)
{
fprintf(stderr,"[1] Bad address %d\n", num);
return 1;
}
if (num & 1)
return (byte1 << 4) | ((byte0 & 0xf0)>>4);
else
return ((byte1 & 0xf) << 8) | byte0;
}
/*
* Puts a code into the FAT table. Is the opposite of fat_decode(). No
* sanity checking is done on the code. Returns a 1 on error.
*/
static void fat12_encode(struct Fs_t *Stream, unsigned int num, unsigned int code)
{
const int start = num * 3 / 2;
unsigned char *address0 = getAddress(Stream, start, FAT_ACCESS_WRITE);
unsigned char *address1 = getAddress(Stream, start+1, FAT_ACCESS_WRITE);
if (num & 1)
{
/* (odd) not on byte boundary */
*address0 = (*address0 & 0x0f) | ((code << 4) & 0xf0);
*address1 = (code >> 4) & 0xff;
}
else
{
/* (even) on byte boundary */
*address0 = code & 0xff;
*address1 = (*address1 & 0xf0) | ((code >> 8) & 0x0f);
}
}
/*
* Fat 16 encoding:
* | byte n | byte n+1 |
* |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
* | | | | | | | | | | | | | | | | |
* | FAT entry k |
*/
static unsigned int fat16_decode(struct Fs_t *Stream, unsigned int num)
{
unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_READ);
return address ? _WORD(address) : 1;
}
static void fat16_encode(struct Fs_t *Stream, unsigned int num, unsigned int code)
{
unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_WRITE);
set_word(address, code);
}
static unsigned int fast_fat16_decode(struct Fs_t *Stream, unsigned int num)
{
unsigned short *address = (unsigned short *) getAddress(Stream, num << 1, FAT_ACCESS_READ);
return address ? *address : 1;
}
static void fast_fat16_encode(struct Fs_t *Stream, unsigned int num, unsigned int code)
{
unsigned short *address = (unsigned short *) getAddress(Stream, num << 1, FAT_ACCESS_WRITE);
*address = code;
}
/*
* Fat 32 encoding
*/
#define FAT32_HIGH 0xf0000000
#define FAT32_ADDR 0x0fffffff
static unsigned int fat32_decode(struct Fs_t *Stream, unsigned int num)
{
unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_READ);
return address ? _DWORD(address) & FAT32_ADDR : 1;
}
static void fat32_encode(struct Fs_t *Stream, unsigned int num, unsigned int code)
{
unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_WRITE);
set_dword(address,(code&FAT32_ADDR) | (_DWORD(address)&FAT32_HIGH));
}
static unsigned int fast_fat32_decode(struct Fs_t *Stream, unsigned int num)
{
unsigned int *address = (unsigned int *) getAddress(Stream, num << 2, FAT_ACCESS_READ);
return address ? *address & FAT32_ADDR : 1;
}
static void fast_fat32_encode(struct Fs_t *Stream, unsigned int num, unsigned int code)
{
unsigned int *address = (unsigned int *) getAddress(Stream, num << 2, FAT_ACCESS_WRITE);
*address = (*address & FAT32_HIGH) | (code & FAT32_ADDR);
}
/*
* Write the FAT table to the disk. Up to now the FAT manipulation has
* been done in memory. All errors are fatal. (Might not be too smart
* to wait till the end of the program to write the table. Oh well...)
*/
int fat_write(struct Fs_t *This)
{
unsigned int i;
unsigned int j;
unsigned int bit;
unsigned int slot;
int ret;
int fat_start;
if (!This->fat_dirty)
return 0;
unsigned int dups = This->num_fat;
if (This->fat_error)
dups = 1;
for(i = 0; i < dups; i++)
{
j = 0;
fat_start = This->fat_start + i*This->fat_len;
for (slot = 0; j < This->fat_len; slot++)
{
if(!This->FatMap[slot].dirty)
{
j += SECT_PER_ENTRY;
continue;
}
for(bit = 0; bit < SECT_PER_ENTRY && j < This->fat_len; bit++, j++)
{
if(!(This->FatMap[slot].dirty & (ONE << bit)))
continue;
ret = fatWriteSector(This,j,slot, bit, i);
if (ret < (int) This->sector_size)
{
if (ret < 0)
{
perror("error in fat_write");
return -1; // TODO: check in caller
}
fprintf(stderr, "end of file in fat_write\n");
return -1; // TODO: check in caller
}
/* if last dupe, zero it out */
if (i == dups - 1)
This->FatMap[slot].dirty &= ~(ONE << bit);
}
}
}
/* write the info sector, if any */
if(This->infoSectorLoc && This->infoSectorLoc != MAX32)
{
/* initialize info sector */
struct InfoSector_t *infoSector = malloc(This->sector_size);
set_dword(infoSector->signature1, INFOSECT_SIGNATURE1);
memset(infoSector->filler1, 0, sizeof(infoSector->filler1));
memset(infoSector->filler2, 0, sizeof(infoSector->filler2));
set_dword(infoSector->signature2, INFOSECT_SIGNATURE2);
set_dword(infoSector->pos, This->last);
set_dword(infoSector->count, This->freeSpace);
set_dword(infoSector->signature3, 0xaa55);
if(forceWriteSector(This, (char *)infoSector, This->infoSectorLoc, 1) != (signed int) This->sector_size)
fprintf(stderr,"Trouble writing the info sector\n");
free(infoSector);
}
This->fat_dirty = 0;
This->lastFatAccessMode = FAT_ACCESS_READ;
return 0;
}
static void set_fat12(struct Fs_t *This)
{
This->fat_bits = 12;
This->end_fat = 0xfff;
This->last_fat = 0xff6;
This->fat_decode = fat12_decode;
This->fat_encode = fat12_encode;
}
static char word_endian_test[] = { 0x34, 0x12 };
static void set_fat16(struct Fs_t *This)
{
This->fat_bits = 16;
This->end_fat = 0xffff;
This->last_fat = 0xfff6;
if(sizeof(unsigned short) == 2 && * (unsigned short *) word_endian_test == 0x1234) {
This->fat_decode = fast_fat16_decode;
This->fat_encode = fast_fat16_encode;
}
else
{
This->fat_decode = fat16_decode;
This->fat_encode = fat16_encode;
}
}
static char dword_endian_test[] = { 0x78, 0x56, 0x34, 0x12 };
static void set_fat32(struct Fs_t *This)
{
This->fat_bits = 32;
This->end_fat = 0xfffffff;
This->last_fat = 0xffffff6;
if(sizeof(unsigned int) == 4 && * (unsigned int *) dword_endian_test == 0x12345678)
{
This->fat_decode = fast_fat32_decode;
This->fat_encode = fast_fat32_encode;
}
else
{
This->fat_decode = fat32_decode;
This->fat_encode = fat32_encode;
}
}
/*
* Read the first sector of FAT table into memory. Crude error detection on
* wrong FAT encoding scheme.
*/
static int check_media_type(struct Fs_t *This, union bootsector UNUSED(*boot), unsigned int tot_sectors)
{
This->num_clus = (tot_sectors - This->clus_start) / This->cluster_size;
This->FatMap = GetFatMap(This);
if (This->FatMap == NULL)
{
perror("alloc fat map");
return -1;
}
unsigned char* address = getAddress(This, 0, FAT_ACCESS_READ);
if(!address)
{
fprintf(stderr, "Could not read first FAT sector\n");
return -1;
}
return 0;
}
static int fat_32_read(struct Fs_t *This, union bootsector *boot, unsigned int tot_sectors)
{
int size;
This->fat_len = DWORD(ext.fat32.bigFat);
This->writeAllFats = !(boot->boot.ext.fat32.extFlags[0] & 0x80);
This->primaryFat = boot->boot.ext.fat32.extFlags[0] & 0xf;
This->rootCluster = DWORD(ext.fat32.rootCluster);
This->clus_start = This->fat_start + This->num_fat * This->fat_len;
/* read the info sector */
size = This->sector_size;
This->infoSectorLoc = WORD(ext.fat32.infoSector);
if (This->sector_size >= 512 && This->infoSectorLoc && This->infoSectorLoc != MAX32)
{
struct InfoSector_t *infoSector = (struct InfoSector_t *) malloc(size);
if (forceReadSector(This, (char *)infoSector, This->infoSectorLoc, 1) == (signed int) This->sector_size
&& _DWORD(infoSector->signature1) == INFOSECT_SIGNATURE1
&& _DWORD(infoSector->signature2) == INFOSECT_SIGNATURE2)
{
This->freeSpace = _DWORD(infoSector->count);
This->last = _DWORD(infoSector->pos);
}
free(infoSector);
}
set_fat32(This);
return check_media_type(This, boot, tot_sectors);
}
static int old_fat_read(struct Fs_t *This, union bootsector *boot, int UNUSED(config_fat_bits), size_t tot_sectors, int nodups)
{
This->writeAllFats = 1;
This->primaryFat = 0;
This->dir_start = This->fat_start + This->num_fat * This->fat_len;
This->clus_start = This->dir_start + This->dir_len;
This->infoSectorLoc = MAX32;
if(nodups)
This->num_fat = 1;
if(check_media_type(This,boot, tot_sectors))
return -1;
if(This->num_clus >= FAT12)
set_fat16(This); /* third FAT byte must be 0xff */
else
set_fat12(This);
return 0;
}
/*
* Read the first sector of the FAT table into memory and initialize
* structures.
*/
int fat_read(struct Fs_t *This, union bootsector *boot, int fat_bits, size_t tot_sectors, int nodups)
{
This->fat_error = 0;
This->fat_dirty = 0;
This->last = MAX32;
This->freeSpace = MAX32;
This->lastFatSectorNr = 0;
This->lastFatSectorData = 0;
return (This->fat_len) ? old_fat_read(This, boot, fat_bits, tot_sectors, nodups) : fat_32_read(This, boot, tot_sectors);
}
unsigned int fatDecode(struct Fs_t *This, unsigned int pos)
{
unsigned int ret = This->fat_decode(This, pos);
if(ret && (ret < 2 || ret > This->num_clus+1) && ret < This->last_fat)
{
fprintf(stderr, "Bad FAT entry %d at %d\n", ret, pos);
This->fat_error++;
}
return ret;
}
/* append a new cluster */
void fatAppend(struct Fs_t *This, unsigned int pos, unsigned int newpos)
{
This->fat_encode(This, pos, newpos);
This->fat_encode(This, newpos, This->end_fat);
if(This->freeSpace != MAX32)
This->freeSpace--;
}
/* de-allocates the given cluster */
void fatDeallocate(struct Fs_t *This, unsigned int pos)
{
This->fat_encode(This, pos, 0);
if(This->freeSpace != MAX32)
This->freeSpace++;
}
/* allocate a new cluster */
void fatAllocate(struct Fs_t *This, unsigned int pos, unsigned int value)
{
This->fat_encode(This, pos, value);
if(This->freeSpace != MAX32)
This->freeSpace--;
}
unsigned int get_next_free_cluster(struct Fs_t *This, unsigned int last)
{
unsigned int i;
if (This->last != MAX32)
last = This->last;
if (last < 2 || last >= This->num_clus+1)
last = 1;
for (i = last + 1; i < This->num_clus + 2; i++)
{
unsigned int r = fatDecode(This, i);
if(r == 1)
goto exit_0;
if (!r)
{
This->last = i;
return i;
}
}
for(i = 2; i < last + 1; i++)
{
unsigned int r = fatDecode(This, i);
if(r == 1)
goto exit_0;
if (!r)
{
This->last = i;
return i;
}
}
fprintf(stderr,"No free cluster %d %d\n", This->preallocatedClusters, This->last);
return 1;
exit_0:
fprintf(stderr, "FAT error\n");
return 1;
}
int fat_error(struct Stream_t *Dir)
{
struct Stream_t *Stream = GetFs(Dir);
DeclareThis(struct Fs_t);
if(This->fat_error)
fprintf(stderr,"Fat error detected\n");
return This->fat_error;
}
int fat32RootCluster(struct Stream_t *Dir)
{
struct Stream_t *Stream = GetFs(Dir);
DeclareThis(struct Fs_t);
return This->fat_bits == 32 ? This->rootCluster : 0;
}
/*
* Ensure that there is a minimum of total sectors free
*/
int getfreeMinClusters(struct Stream_t *Dir, size_t size)
{
struct Stream_t *Stream = GetFs(Dir);
DeclareThis(struct Fs_t);
if(This->freeSpace != MAX32)
{
if (This->freeSpace >= size)
return 1;
else
{
fprintf(stderr, "Disk full\n");
return 0;
}
}
size_t total = 0;
/* we start at the same place where we'll start later to actually
* allocate the sectors. That way, the same sectors of the FAT, which
* are already loaded during getfreeMin will be able to be reused
* during get_next_free_cluster */
unsigned int last = This->last;
if (last < 2 || last >= This->num_clus + 2)
last = 1;
unsigned int i;
for (i=last+1; i< This->num_clus+2; i++)
{
unsigned int r = fatDecode(This, i);
if(r == 1)
goto exit_0;
if (!r)
total++;
if(total >= size)
return 1;
}
for(i=2; i < last+1; i++)
{
unsigned int r = fatDecode(This, i);
if(r == 1)
goto exit_0;
if (!r)
total++;
if(total >= size)
return 1;
}
fprintf(stderr, "Disk full\n");
return 0;
exit_0:
fprintf(stderr, "FAT error\n");
return 0;
}
unsigned int getStart(struct Stream_t *Dir, struct directory *dir)
{
struct Stream_t *Stream = GetFs(Dir);
unsigned int first = START(dir);
if(fat32RootCluster(Stream))
first |= STARTHI(dir) << 16;
return first;
}
int fs_free(struct Stream_t *Stream)
{
DeclareThis(struct Fs_t);
if (This->FatMap)
{
const int nr_entries = (This->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY;
for (int i = 0; i < nr_entries; i++)
if (This->FatMap[i].data)
free(This->FatMap[i].data);
free(This->FatMap);
}
if (This->cp)
cp_close(This->cp);
return 0;
}

View file

@ -1,30 +0,0 @@
/* Copyright 1996-2005,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_FAT_H
#define MTOOLS_FAT_H
#include <stddef.h>
struct Stream_t;
struct directory;
int getfreeMinClusters(struct Stream_t *Stream, size_t ref);
unsigned int getStart(struct Stream_t *Dir, struct directory *dir);
#endif

View file

@ -1,212 +0,0 @@
/* Copyright 1986-1992 Emmet P. Gray.
* Copyright 1996-1998,2000-2002,2005,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*
* mlabel.c
* Make an MSDOS volume label
*/
#include "fatlabel.h"
#include "msdos.h"
#include "nameclash.h"
#include "init.h"
#include "file.h"
#include "directory.h"
#include "force_io.h"
#include "file_name.h"
#include <wctype.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
/**
* Wipe the given entry
*/
static void wipeEntry(struct direntry_t *entry)
{
struct direntry_t longNameEntry;
initializeDirentry(&longNameEntry, entry->Dir);
for(int i = entry->beginSlot; i< entry->endSlot; i++)
{
int error;
longNameEntry.entry=i;
dir_read(&longNameEntry, &error);
if(error)
break;
longNameEntry.dir.name[0] = (char) DELMARK;
dir_write(&longNameEntry);
}
entry->dir.name[0] = (char) DELMARK;
dir_write(entry);
}
void label_name(struct doscp_t *cp, const char *filename, int *mangled, struct dos_name_t *ans)
{
memset(ans, ' ', 8 + 3);
ans->sentinel = '\0';
wchar_t wbuffer[12];
int len = native_to_wchar(filename, wbuffer, 11, 0, 0);
if (len > 11)
{
*mangled = 1;
len = 11;
}
else
*mangled = 0;
int have_lower = 0;
int have_upper = 0;
int i = 0;
for(i = 0; i < len; i++)
{
if (islower(wbuffer[i]))
have_lower = 1;
if (isupper(wbuffer[i]))
have_upper = 1;
wbuffer[i] = towupper(wbuffer[i]);
if (wcschr(L"^+=/[]:,?*\\<>|\".", wbuffer[i]))
{
*mangled = 1;
wbuffer[i] = '~';
}
}
if (have_lower && have_upper)
*mangled = 1;
wchar_to_dos(cp, wbuffer, ans->base, len, mangled);
}
int labelit(struct dos_name_t* dosname, struct direntry_t* entry)
{
time_t now = time(NULL);
mk_entry(dosname, 0x8, 0, 0, now, &entry->dir);
return 0;
}
int fatlabel_set_label(const char* device_name, const char* new_label)
{
if (strlen(new_label) > VBUFSIZE)
return -1;
/*
* 1. Init clash handling
*/
struct ClashHandling_t ch;
init_clash_handling(&ch);
ch.name_converter = label_name;
ch.ignore_entry = -2;
/*
* 2. Open root dir
*/
struct Stream_t* RootDir = fs_init(device_name, O_RDWR);
if (RootDir)
RootDir = OpenRoot(RootDir);
if (!RootDir)
{
fprintf(stderr, "Opening root dir failed.\n");
return -2;
}
/*
* 3. Init dir entry
*/
struct direntry_t entry;
initializeDirentry(&entry, RootDir);
/*
* 4. Lookup vfat
*/
char longname[VBUFSIZE];
char shortname[45];
if (vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY, shortname, longname) == -2)
{
fprintf(stderr, "Looking up vfat failed.\n");
free_stream(&RootDir);
return -3;
}
/*
* 5. Wipe existing entry.
*/
if (!isNotFound(&entry))
{
/* if we have a label, wipe it out before putting new one */
entry.dir.attr = 0; /* for old mlabel */
wipeEntry(&entry);
}
/*
* 6. Write new entry
*/
ch.ignore_entry = 1;
/* don't try to write the label if it's empty */
int result = strlen(new_label) ? mwrite_one(RootDir, new_label, labelit, &ch) : 0;
/*
* 7. Load FAT boot record
*/
union bootsector boot;
struct Stream_t* Fs = GetFs(RootDir);
int have_boot = force_read(Fs, boot.characters, 0, sizeof(boot)) == sizeof(boot);
struct label_blk_t* labelBlock = WORD_S(fatlen) ? &boot.boot.ext.old.labelBlock : &boot.boot.ext.fat32.labelBlock;
/*
* 8. Get "dosconvert" struct
*/
struct dos_name_t dosname;
struct doscp_t* cp = GET_DOSCONVERT(Fs);
/*
* 9. Convert label
*/
int mangled = 0;
label_name(cp, new_label, &mangled, &dosname);
/*
* 10. Overwrite FAT boot record
*/
if (have_boot && boot.boot.descr >= 0xf0 && labelBlock->dos4 == 0x29)
{
strncpy(labelBlock->label, dosname.base, 11);
force_write(Fs, (char *)&boot, 0, sizeof(boot));
}
free_stream(&RootDir);
fs_close(Fs);
return result;
}

View file

@ -1,33 +0,0 @@
/***************************************************************************
* Copyright (C) 2010 by Volker Lanz <vl@fidra.de> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#ifndef MTOOLS_MLABEL_H
#define MTOOLS_MLABEL_H
#ifdef __cplusplus
extern "C" {
#endif
int __attribute__((visibility("default"))) fatlabel_set_label(const char* device_name, const char* new_label);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,537 +0,0 @@
/* Copyright 1996-1999,2001-2003,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "msdos.h"
#include "stream.h"
#include "mtools.h"
#include "file.h"
#include "htable.h"
#include "dirCache.h"
#include "directory.h"
#include "init.h"
#include "fat.h"
#include "fs.h"
#include "llong.h"
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
struct File_t
{
struct Class_t *Class;
int refs;
struct Fs_t *Fs; /* Filesystem that this fat file belongs to */
struct Stream_t *Buffer;
int (*map)(struct File_t *this, off_t where, size_t *len, int mode, off_t *res);
size_t FileSize;
size_t preallocatedSize;
int preallocatedClusters;
/* Absolute position of first cluster of file */
unsigned int FirstAbsCluNr;
/* Absolute position of previous cluster */
unsigned int PreviousAbsCluNr;
/* Relative position of previous cluster */
unsigned int PreviousRelCluNr;
struct direntry_t direntry;
int hint;
struct dirCache_t *dcp;
unsigned int loopDetectRel;
unsigned int loopDetectAbs;
};
static struct Class_t FileClass;
static struct hashtable *filehash;
static struct File_t *getUnbufferedFile(struct Stream_t *Stream)
{
while(Stream->Class != &FileClass)
Stream = Stream->Next;
return (struct File_t *) Stream;
}
struct dirCache_t **getDirCacheP(struct Stream_t *Stream)
{
return &getUnbufferedFile(Stream)->dcp;
}
struct direntry_t *getDirentry(struct Stream_t *Stream)
{
return &getUnbufferedFile(Stream)->direntry;
}
static int recalcPreallocSize(struct File_t *This)
{
struct Fs_t *Fs = This->Fs;
int clus_size = Fs->cluster_size * Fs->sector_size;
size_t currentClusters = (This->FileSize + clus_size - 1) / clus_size;
size_t neededClusters = (This->preallocatedSize + clus_size - 1) / clus_size;
int neededPrealloc = neededClusters - currentClusters;
if (neededPrealloc < 0)
neededPrealloc = 0;
int r = fsPreallocateClusters(Fs, neededPrealloc - This->preallocatedClusters);
if(r)
return r;
This->preallocatedClusters = neededPrealloc;
return 0;
}
static int _loopDetect(unsigned int* oldrel, unsigned int rel, unsigned int* oldabs, unsigned int absol)
{
if (*oldrel && rel > *oldrel && absol == *oldabs)
{
fprintf(stderr, "loop detected! oldrel=%d newrel=%d abs=%d\n", *oldrel, rel, absol);
return -1;
}
if (rel >= 2 * *oldrel + 1)
{
*oldrel = rel;
*oldabs = absol;
}
return 0;
}
static int loopDetect(struct File_t* This, unsigned int rel, unsigned int absol)
{
return _loopDetect(&This->loopDetectRel, rel, &This->loopDetectAbs, absol);
}
static unsigned int _countBlocks(struct Fs_t *This, unsigned int block)
{
unsigned int blocks = 0;
unsigned int rel = 0;
unsigned int oldabs = 0;
unsigned int oldrel = 0;
while (block <= This->last_fat && block != 1 && block)
{
blocks++;
block = fatDecode(This, block);
rel++;
if (_loopDetect(&oldrel, rel, &oldabs, block) < 0)
block = -1;
}
return blocks;
}
/* returns number of bytes in a directory. Represents a file size, and
* can hence be not bigger than 2^32
*/
static size_t countBytes(struct Stream_t *Dir, unsigned int block)
{
struct Stream_t *Stream = GetFs(Dir);
DeclareThis(struct Fs_t);
return _countBlocks(This, block) * This->sector_size * This->cluster_size;
}
static int normal_map(struct File_t *This, off_t where, size_t *len, int mode, off_t *res)
{
size_t end;
int NrClu; /* number of clusters to read */
struct Fs_t *Fs = This->Fs;
*res = 0;
int clus_size = Fs->cluster_size * Fs->sector_size;
int offset = where % clus_size;
if (mode == MT_READ)
maximize(*len, This->FileSize - where);
if (*len == 0)
return 0;
unsigned int NewCluNr;
if (This->FirstAbsCluNr < 2)
{
if( mode == MT_READ || *len == 0)
{
*len = 0;
return 0;
}
NewCluNr = get_next_free_cluster(This->Fs, 1);
if (NewCluNr == 1 )
{
errno = ENOSPC;
return -2;
}
hash_remove(filehash, (void *) This, This->hint);
This->FirstAbsCluNr = NewCluNr;
hash_add(filehash, (void *) This, &This->hint);
fatAllocate(This->Fs, NewCluNr, Fs->end_fat);
}
unsigned int RelCluNr = where / clus_size;
unsigned int CurCluNr;
unsigned int AbsCluNr;
if (RelCluNr >= This->PreviousRelCluNr)
{
CurCluNr = This->PreviousRelCluNr;
AbsCluNr = This->PreviousAbsCluNr;
}
else
{
CurCluNr = 0;
AbsCluNr = This->FirstAbsCluNr;
}
NrClu = (offset + *len - 1) / clus_size;
while (CurCluNr <= RelCluNr + NrClu)
{
if (CurCluNr == RelCluNr)
{
/* we have reached the beginning of our zone. Save
* coordinates */
This->PreviousRelCluNr = RelCluNr;
This->PreviousAbsCluNr = AbsCluNr;
}
NewCluNr = fatDecode(This->Fs, AbsCluNr);
if (NewCluNr == 1 || NewCluNr == 0)
{
fprintf(stderr,"Fat problem while decoding %d %x\n", AbsCluNr, NewCluNr);
return -3; // TODO: check return code in caller
}
if (CurCluNr == RelCluNr + NrClu)
break;
if (NewCluNr > Fs->last_fat && mode == MT_WRITE)
{
/* if at end, and writing, extend it */
NewCluNr = get_next_free_cluster(This->Fs, AbsCluNr);
if (NewCluNr == 1) /* no more space */
{
errno = ENOSPC;
return -2;
}
fatAppend(This->Fs, AbsCluNr, NewCluNr);
}
if (CurCluNr < RelCluNr && NewCluNr > Fs->last_fat)
{
*len = 0;
return 0;
}
if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
break;
CurCluNr++;
AbsCluNr = NewCluNr;
if(loopDetect(This, CurCluNr, AbsCluNr))
{
errno = EIO;
return -2;
}
}
maximize(*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
end = where + *len;
if((*len + offset) / clus_size + This->PreviousAbsCluNr-2 > Fs->num_clus)
{
fprintf(stderr, "cluster too big\n");
return -3; // TODO: check return code in caller
}
*res = sectorsToBytes((struct Stream_t*)Fs, (This->PreviousAbsCluNr-2) * Fs->cluster_size + Fs->clus_start) + offset;
return 1;
}
static int root_map(struct File_t *This, off_t where, size_t *len, int UNUSED(mode), off_t *res)
{
struct Fs_t *Fs = This->Fs;
if(Fs->dir_len * Fs->sector_size < (size_t) where)
{
*len = 0;
errno = ENOSPC;
return -2;
}
maximize(*len, Fs->dir_len * Fs->sector_size - where);
if (*len == 0)
return 0;
*res = sectorsToBytes((struct Stream_t*)Fs, Fs->dir_start) + where;
return 1;
}
static int read_file(struct Stream_t *Stream, char *buf, off_t iwhere, size_t len)
{
DeclareThis(struct File_t);
off_t pos;
off_t where = truncBytes32(iwhere);
struct Stream_t *Disk = This->Fs->Next;
int err = This->map(This, where, &len, MT_READ, &pos);
return (err <= 0) ? err : READS(Disk, buf, pos, len);
}
static int write_file(struct Stream_t *Stream, char *buf, off_t iwhere, size_t len)
{
DeclareThis(struct File_t);
off_t pos;
struct Stream_t *Disk = This->Fs->Next;
off_t where = truncBytes32(iwhere);
const size_t requestedLen = len;
int err = This->map(This, where, &len, MT_WRITE, &pos);
if (err <= 0)
return err;
int ret = WRITES(Disk, buf, pos, len);
if(ret > (signed int) requestedLen)
ret = requestedLen;
if (ret > 0 && where + ret > (off_t) This->FileSize)
This->FileSize = where + ret;
recalcPreallocSize(This);
return ret;
}
static int free_file(struct Stream_t *Stream)
{
DeclareThis(struct File_t);
struct Fs_t *Fs = This->Fs;
fsPreallocateClusters(Fs, -This->preallocatedClusters);
free_stream(&This->direntry.Dir);
freeDirCache(Stream);
return hash_remove(filehash, (void *) Stream, This->hint);
}
static int flush_file(struct Stream_t *Stream)
{
DeclareThis(struct File_t);
struct direntry_t *entry = &This->direntry;
if (isRootDir(Stream))
return 0;
if (This->FirstAbsCluNr != getStart(entry->Dir, &entry->dir))
{
set_word(entry->dir.start, This->FirstAbsCluNr & 0xffff);
set_word(entry->dir.startHi, This->FirstAbsCluNr >> 16);
dir_write(entry);
}
return 0;
}
static int pre_allocate_file(struct Stream_t *Stream, size_t isize)
{
DeclareThis(struct File_t);
size_t size = truncBytes32(isize);
if (size > This->FileSize && size > This->preallocatedSize)
{
This->preallocatedSize = size;
return recalcPreallocSize(This);
}
return 0;
}
static struct Class_t FileClass =
{
read_file,
write_file,
flush_file, /* flush */
free_file, /* free */
0, /* get_geom */
0, /* get_file_data */
pre_allocate_file,
get_dosConvert_pass_through
};
static unsigned int getAbsCluNr(struct File_t *This)
{
if(This->FirstAbsCluNr)
return This->FirstAbsCluNr;
if(isRootDir((struct Stream_t *) This))
return 0;
return 1;
}
static unsigned int func1(void *Stream)
{
DeclareThis(struct File_t);
return getAbsCluNr(This) ^ (long) This->Fs;
}
static unsigned int func2(void *Stream)
{
DeclareThis(struct File_t);
return getAbsCluNr(This);
}
static int comp(void *Stream, void *Stream2)
{
DeclareThis(struct File_t);
struct File_t *This2 = (struct File_t *) Stream2;
return This->Fs != This2->Fs || getAbsCluNr(This) != getAbsCluNr(This2);
}
static void init_hash(void)
{
static int is_initialised = 0;
if(!is_initialised)
{
make_ht(func1, func2, comp, 20, &filehash);
is_initialised = 1;
}
}
static struct Stream_t *_internalFileOpen(struct Stream_t* Dir, unsigned int first, size_t size, struct direntry_t *entry)
{
struct Stream_t *Stream = GetFs(Dir);
DeclareThis(struct Fs_t);
struct File_t Pattern;
struct File_t *File;
init_hash();
This->refs++;
if (first != 1)
{
/* we use the illegal cluster 1 to mark newly created files.
* do not manage those by hashtable */
Pattern.Fs = This;
Pattern.Class = &FileClass;
Pattern.map = (first || (entry && !IS_DIR(entry))) ? normal_map : root_map;
Pattern.FirstAbsCluNr = first;
Pattern.loopDetectRel = 0;
Pattern.loopDetectAbs = first;
if (!hash_lookup(filehash, (T_HashTableEl) &Pattern, (T_HashTableEl **)&File, 0))
{
File->refs++;
This->refs--;
return (struct Stream_t*) File;
}
}
File = New(struct File_t);
if (!File)
return NULL;
File->dcp = 0;
File->preallocatedClusters = 0;
File->preallocatedSize = 0;
/* memorize dir for date and attrib */
File->direntry = *entry;
if (entry->entry == -3)
File->direntry.Dir = (struct Stream_t *) File; /* root directory */
else
copy_stream(File->direntry.Dir);
File->Class = &FileClass;
File->Fs = This;
File->map = (first || (entry && !IS_DIR(entry))) ? normal_map : root_map;
File->FirstAbsCluNr = (first == 1) ? 0 : first;
File->loopDetectRel = 0;
File->loopDetectAbs = 0;
File->PreviousRelCluNr = 0xffff;
File->FileSize = size;
File->refs = 1;
File->Buffer = 0;
hash_add(filehash, (void *) File, &File->hint);
return (struct Stream_t *) File;
}
struct Stream_t* OpenRoot(struct Stream_t* Dir)
{
const unsigned int num = fat32RootCluster(Dir);
struct direntry_t entry;
memset(&entry, 0, sizeof(struct direntry_t));
/* make the directory entry */
entry.entry = -3;
entry.name[0] = '\0';
mk_entry_from_base("/", ATTR_DIR, num, 0, 0, &entry.dir);
size_t size;
if (num)
size = countBytes(Dir, num);
else
{
struct Fs_t* Fs = (struct Fs_t*) GetFs(Dir);
size = Fs->dir_len * Fs->sector_size;
}
struct Stream_t* file = _internalFileOpen(Dir, num, size, &entry);
bufferize(&file);
return file;
}
int isRootDir(struct Stream_t *Stream)
{
struct File_t *This = getUnbufferedFile(Stream);
return This->map == root_map;
}

View file

@ -1,29 +0,0 @@
/* Copyright 1996,1997,2001,2002,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_FILE_H
#define MTOOLS_FILE_H
struct Stream_t;
struct dirCache_t;
struct Stream_t *OpenRoot(struct Stream_t *Dir);
struct dirCache_t **getDirCacheP(struct Stream_t *Stream);
int isRootDir(struct Stream_t *Stream);
#endif

View file

@ -1,112 +0,0 @@
/* Copyright 1995 David C. Niemi
* Copyright 1996-1998,2000-2002,2008,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "file_name.h"
#include <string.h>
#include <ctype.h>
typedef enum Case_l {
NONE,
UPPER,
LOWER
} Case_t;
/*
* Get rid of spaces in an MSDOS 'raw' name (one that has come from the
* directory structure) so that it can be used for regular expression
* matching with a Unix filename. Also used to 'unfix' a name that has
* been altered by dos_name().
*/
wchar_t *unix_name(struct doscp_t *dosCp, const char *base, const char *ext, char Case, wchar_t *ret)
{
char tname[9];
strncpy(tname, base, 8);
tname[8] = '\0';
char *s;
if ((s = strchr(tname, ' ')))
*s = '\0';
int i;
if(Case & BASECASE)
for(i = 0;i < 8 && tname[i]; i++)
tname[i] = tolower(tname[i]);
char text[4];
strncpy(text, ext, 3);
text[3] = '\0';
if ((s = strchr(text, ' ')))
*s = '\0';
if(Case & EXTCASE)
for(i = 0; i < 3 && text[i]; i++)
text[i] = tolower(text[i]);
char ans[13];
if (*text)
{
strcpy(ans, tname);
strcat(ans, ".");
strcat(ans, text);
}
else
strcpy(ans, tname);
/* fix special characters (above 0x80) */
dos_to_wchar(dosCp, ans, ret, 12);
return ret;
}
/* If null encountered, set *end to 0x40 and write nulls rest of way
* 950820: Win95 does not like this! It complains about bad characters.
* So, instead: If null encountered, set *end to 0x40, write the null, and
* write 0xff the rest of the way (that is what Win95 seems to do; hopefully
* that will make it happy)
*/
/* Always return num */
int unicode_write(wchar_t *in, struct unicode_char *out, int num, int *end_p)
{
int j;
for (j = 0; j < num; ++j)
{
if (*end_p) /* Fill with 0xff */
out->uchar = out->lchar = (char) 0xff;
else
{
out->uchar = *in >> 8;
out->lchar = *in;
if (! *in)
*end_p = VSE_LAST;
}
++out;
++in;
}
return num;
}

View file

@ -1,50 +0,0 @@
/* Copyright 2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FILE_NAME_H
#define FILE_NAME_H
#include <wchar.h>
#include <stddef.h>
struct doscp_t;
/**
* raw dos-name coming straight from the directory entry
* MYFILE TXT
*/
struct dos_name_t
{
char base[8];
char ext[3];
char sentinel;
};
struct doscp_t;
int dos_to_wchar(struct doscp_t *fromDos, char *dos, wchar_t *wchar, size_t len);
void wchar_to_dos(struct doscp_t *toDos, wchar_t *wchar, char *dos, size_t len, int *mangled);
struct doscp_t *cp_open(int codepage);
void cp_close(struct doscp_t *cp);
int wchar_to_native(const wchar_t *wchar, char *native, size_t len);
int native_to_wchar(const char *native, wchar_t *wchar, size_t len, const char *end, int *mangled);
wchar_t *unix_name(struct doscp_t *fromDos, const char *base, const char *ext, char Case, wchar_t *answer);
#endif

View file

@ -1,60 +0,0 @@
/* Copyright 1996,1997,1999,2001,2002,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*
* Force I/O to be done to complete transfer length
*
* written by:
*
* Alain L. Knaff
* alain@knaff.lu
*
*/
#include "msdos.h"
#include "stream.h"
#include <stddef.h>
static int force_io(struct Stream_t *Stream, char *buf, off_t start, size_t len, int (*io)(struct Stream_t *, char *, off_t, size_t))
{
int done = 0;
while(len)
{
int ret = io(Stream, buf, start, len);
if (ret <= 0 )
return done ? done : ret;
start += ret;
done += ret;
len -= ret;
buf += ret;
}
return done;
}
int force_write(struct Stream_t *Stream, char *buf, off_t start, size_t len)
{
return force_io(Stream, buf, start, len, Stream->Class->write);
}
int force_read(struct Stream_t *Stream, char *buf, off_t start, size_t len)
{
return force_io(Stream, buf, start, len, Stream->Class->read);
}

View file

@ -1,31 +0,0 @@
/* Copyright 1996-1999,2001,2002,2005,2006,2008,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_FORCE_IO_H
#define MTOOLS_FORCE_IO_H
#include <sys/types.h>
#include <stddef.h>
struct Stream_t;
int force_write(struct Stream_t *Stream, char *buf, off_t start, size_t len);
int force_read(struct Stream_t *Stream, char *buf, off_t start, size_t len);
#endif

View file

@ -1,108 +0,0 @@
/* Copyright 1996,1997,2001,2002,2007,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_FS_H
#define MTOOLS_FS_H
struct Stream_t;
struct Class_t;
struct doscp_t;
struct FsPublic_t
{
struct Class_t *Class;
int refs;
struct Stream_t *Next;
struct Stream_t *Buffer;
int serialized;
unsigned long serial_number;
int cluster_size;
unsigned int sector_size;
};
typedef enum fatAccessMode_t
{
FAT_ACCESS_READ,
FAT_ACCESS_WRITE
} fatAccessMode_t;
struct Fs_t
{
struct Class_t *Class;
int refs;
struct Stream_t *Next;
struct Stream_t *Buffer;
int serialized;
unsigned long serial_number;
unsigned int cluster_size;
unsigned int sector_size;
int fat_error;
unsigned int (*fat_decode)(struct Fs_t *This, unsigned int num);
void (*fat_encode)(struct Fs_t *This, unsigned int num, unsigned int code);
struct Stream_t *Direct;
int fat_dirty;
unsigned int fat_start;
unsigned int fat_len;
unsigned int num_fat;
unsigned int end_fat;
unsigned int last_fat;
int fat_bits; /* must be signed, because we use negative values for special purposes */
struct FatMap_t *FatMap;
unsigned int dir_start;
unsigned int dir_len;
unsigned int clus_start;
unsigned int num_clus;
/* fat 32 */
unsigned int primaryFat;
unsigned int writeAllFats;
unsigned int rootCluster;
unsigned int infoSectorLoc;
unsigned int last; /* last sector allocated, or MAX32 if unknown */
unsigned int freeSpace; /* free space, or MAX32 if unknown */
int preallocatedClusters;
int lastFatSectorNr;
unsigned char *lastFatSectorData;
fatAccessMode_t lastFatAccessMode;
int sectorMask;
int sectorShift;
struct doscp_t *cp;
};
int fs_free(struct Stream_t *Stream);
unsigned int get_next_free_cluster(struct Fs_t *Fs, unsigned int last);
unsigned int fatDecode(struct Fs_t *This, unsigned int pos);
void fatAppend(struct Fs_t *This, unsigned int pos, unsigned int newpos);
void fatDeallocate(struct Fs_t *This, unsigned int pos);
void fatAllocate(struct Fs_t *This, unsigned int pos, unsigned int value);
int fat_read(struct Fs_t *This, union bootsector *boot, int fat_bits, size_t tot_sectors, int nodups);
int fat_write(struct Fs_t *This);
struct Stream_t* fs_init(const char* deviceName, int mode);
int fat_error(struct Stream_t *Dir);
int fat32RootCluster(struct Stream_t *Dir);
#endif

View file

@ -1,234 +0,0 @@
/* Copyright 1996,1997,2001,2002,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*
* hash.c - hash table.
*/
#include "htable.h"
#include "mtools.h"
#include <stdlib.h>
#include <stdio.h>
struct hashtable {
T_HashFunc f1,f2;
T_ComparFunc compar;
int size; /* actual size of the array */
int fill; /* number of deleted or in use slots */
int inuse; /* number of slots in use */
int max; /* maximal number of elements to keep efficient */
T_HashTableEl *entries;
};
static const int sizes[]=
{
5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853,
25717, 51437, 102877, 205759, 411527, 823117, 1646237,
3292489, 6584983, 13169977, 26339969, 52679969, 105359939,
210719881, 421439783, 842879579, 1685759167, 0
};
static int deleted=0;
static int unallocated=0;
static int alloc_ht(struct hashtable *H, int size)
{
int i;
for(i = 0; sizes[i]; i++)
if (sizes[i] > size*4)
break;
if (!sizes[i])
for(i = 0; sizes[i]; i++)
if (sizes[i] > size*2 )
break;
if (!sizes[i])
for(i = 0; sizes[i]; i++)
if (sizes[i] > size)
break;
if(!sizes[i])
return -1;
size = sizes[i];
if(size < H->size)
size = H->size; /* never shrink the table */
H->max = size * 4 / 5 - 2;
H->size = size;
H->fill = 0;
H->inuse = 0;
H->entries = NewArray(size, T_HashTableEl);
if (H->entries == NULL)
return -1; /* out of memory error */
for(i = 0; i < size; i++)
H->entries[i] = &unallocated;
return 0;
}
int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, int size, struct hashtable **H)
{
*H = New(struct hashtable);
if (*H == NULL)
return -1; /* out of memory error */
(*H)->f1 = f1;
(*H)->f2 = f2;
(*H)->compar = c;
(*H)->size = 0;
if(alloc_ht(*H,size))
return -1;
return 0;
}
/* add into hash table without checking for repeats */
static int _hash_add(struct hashtable *H,T_HashTableEl *E, int *hint)
{
int pos = H->f1(E) % H->size;
int f2 = -1;
int ctr = 0;
while (H->entries[pos] != &unallocated && H->entries[pos] != &deleted)
{
if (f2 == -1)
f2 = H->f2(E) % (H->size - 1);
pos = (pos + f2 + 1) % H->size;
ctr++;
}
if(H->entries[pos] == &unallocated)
H->fill++; /* only increase fill if the previous element was not yet
* counted, i.e. unallocated */
H->inuse++;
H->entries[pos] = E;
if(hint)
*hint = pos;
return 0;
}
static int rehash(struct hashtable *H)
{
/* resize the table */
int size = H->size;
T_HashTableEl *oldentries = H->entries;
if(alloc_ht(H,((H->inuse+1)*4+H->fill)/5))
return -1;
int i;
for(i = 0; i < size; i++)
{
if (oldentries[i] != &unallocated && oldentries[i] != &deleted)
_hash_add(H, oldentries[i], 0);
}
free(oldentries);
return 0;
}
int hash_add(struct hashtable *H, T_HashTableEl *E, int *hint)
{
if (H->fill >= H->max)
rehash(H);
if (H->fill == H->size)
return -1; /*out of memory error */
return _hash_add(H,E, hint);
}
/* add into hash table without checking for repeats */
static int _hash_lookup(struct hashtable *H,T_HashTableEl *E, T_HashTableEl **E2, int *hint, int isIdentity)
{
int pos = H->f1(E) % H->size;
int ttl = H->size;
int f2 = -1;
int upos = -1;
while(ttl && H->entries[pos] != &unallocated && (H->entries[pos] == &deleted
|| ((isIdentity || H->compar(H->entries[pos], E) != 0) && (!isIdentity || H->entries[pos] != E))))
{
if (f2 == -1)
f2 = H->f2(E) % (H->size - 1);
if (upos == -1 && H->entries[pos] == &deleted)
upos = pos;
pos = (pos + f2 + 1) % H->size;
ttl--;
}
if(H->entries[pos] == &unallocated || !ttl)
return -1;
if (upos != -1)
{
H->entries[upos] = H->entries[pos];
H->entries[pos] = &deleted;
pos = upos;
}
if(hint)
*hint = pos;
*E2 = H->entries[pos];
return 0;
}
int hash_lookup(struct hashtable *H,T_HashTableEl *E, T_HashTableEl **E2, int *hint)
{
return _hash_lookup(H, E, E2, hint, 0);
}
/* add into hash table without checking for repeats */
int hash_remove(struct hashtable *H,T_HashTableEl *E, int hint)
{
T_HashTableEl *E2;
if (hint >=0 && hint < H->size && H->entries[hint] == E)
{
H->inuse--;
H->entries[hint] = &deleted;
return 0;
}
if (_hash_lookup(H, E, &E2, &hint, 1))
{
fprintf(stderr, "Removing non-existent entry\n");
return -1;
}
H->inuse--;
H->entries[hint] = &deleted;
return 0;
}

View file

@ -1,35 +0,0 @@
/* Copyright 1996,1997,2001,2002,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*
* hashtable
*/
#ifndef MTOOLS_HTABLE_H
#define MTOOLS_HTABLE_H
struct hashtable;
typedef void *T_HashTableEl;
typedef unsigned int (*T_HashFunc)(void *);
typedef int (*T_ComparFunc)(void *, void *);
int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, int size, struct hashtable **H);
int hash_add(struct hashtable *H, T_HashTableEl *E, int *hint);
int hash_remove(struct hashtable *H, T_HashTableEl *E, int hint);
int hash_lookup(struct hashtable *H, T_HashTableEl *E, T_HashTableEl **E2, int *hint);
#endif

View file

@ -1,342 +0,0 @@
/* Copyright 1986-1992 Emmet P. Gray.
* Copyright 1996-2002,2006-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "msdos.h"
#include "stream.h"
#include "mtools.h"
#include "fs.h"
#include "plain_io.h"
#include "buffer.h"
#include "file_name.h"
#include "fat.h"
#include "force_io.h"
#include "devices.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define BOOTSIZE 512
/*
* Read the boot sector. We glean the disk parameters from this sector.
*/
static int read_boot(struct Stream_t *Stream, union bootsector * boot, int size)
{
/* read the first sector, or part of it */
if(!size)
size = BOOTSIZE;
if(size > MAX_BOOT)
size = MAX_BOOT;
if (force_read(Stream, boot->characters, 0, size) != size)
return -1;
return 0;
}
static int fs_flush(struct Stream_t *Stream)
{
DeclareThis(struct Fs_t);
fat_write(This);
return 0;
}
static struct doscp_t *get_dosConvert(struct Stream_t *Stream)
{
DeclareThis(struct Fs_t);
return This->cp;
}
static unsigned int log_2(int size)
{
unsigned int i;
for(i = 0; i < 24; i++)
if (1 << i == size)
return i;
return 24;
}
static struct Class_t FsClass = {
read_pass_through, /* read */
write_pass_through, /* write */
fs_flush,
fs_free, /* free */
0, /* set geometry */
get_data_pass_through,
0, /* pre allocate */
get_dosConvert, /* dosconvert */
};
static int get_media_type(struct Stream_t *St, union bootsector *boot)
{
int media;
media = boot->boot.descr;
if(media < 0xf0){
char temp[512];
/* old DOS disk. Media descriptor in the first FAT byte */
/* old DOS disk always have 512-byte sectors */
if (force_read(St,temp,(off_t) 512,512) == 512)
media = (unsigned char) temp[0];
else
media = 0;
} else
media += 0x100;
return media;
}
struct Stream_t *GetFs(struct Stream_t *Fs)
{
while(Fs && Fs->Class != &FsClass)
Fs = Fs->Next;
return Fs;
}
static struct Stream_t *open_stream(const char* deviceName, int mode, struct device *out_dev, union bootsector *boot, int *media, size_t *maxSize)
{
char errmsg[200];
int r;
snprintf(errmsg, 199, "Drive '%s:' not supported", deviceName);
struct device dev;
memset(&dev, 0, sizeof(dev));
dev.name = deviceName;
*out_dev = dev;
struct Stream_t *Stream = SimpleFileOpen(out_dev, &dev, dev.name, mode, errmsg, 0, 1, maxSize);
if (!Stream)
{
fprintf(stderr, "open_stream: opening file failed: %s.\n", errmsg);
return NULL;
}
/* read the boot sector */
if ((r = read_boot(Stream, boot, out_dev->blocksize)) < 0)
{
snprintf(errmsg, 199, "init %s: could not read boot sector", deviceName);
goto out;
}
if((*media = get_media_type(Stream, boot)) <= 0xf0 )
{
if (boot->boot.jump[2]=='L')
snprintf(errmsg, 199, "diskette %s: is Linux LILO, not DOS", deviceName);
else
snprintf(errmsg, 199, "init %s: non DOS media", deviceName);
goto out;
}
/* set new parameters, if needed */
errno = 0;
if (SET_GEOM(Stream, out_dev, &dev, *media, boot))
{
if (errno)
snprintf(errmsg, 199, "Can't set disk parameters for %s: %s", deviceName, strerror(errno));
else
snprintf(errmsg, 199, "Can't set disk parameters for %s", deviceName);
goto out;
}
out:
/* print error msg if needed */
if (Stream == NULL)
{
free_stream(&Stream);
fprintf(stderr, "%s\n", errmsg);
return NULL;
}
return Stream;
}
struct Stream_t *fs_init(const char* deviceName, int mode)
{
struct Fs_t *This = New(struct Fs_t);
if (!This)
{
fprintf(stderr, "fs_init: Creating fs struct failed.\n");
return NULL;
}
This->Direct = NULL;
This->Next = NULL;
This->refs = 1;
This->Buffer = 0;
This->Class = &FsClass;
This->preallocatedClusters = 0;
This->lastFatSectorNr = 0;
This->lastFatAccessMode = 0;
This->lastFatSectorData = 0;
This->last = 0;
struct device dev;
union bootsector boot;
int media = 0;
size_t maxSize = 0;
This->Direct = open_stream(deviceName, mode, &dev, &boot, &media, &maxSize);
if(!This->Direct)
{
fprintf(stderr, "fs_init: opening stream failed.\n");
return NULL;
}
This->sector_size = WORD_S(secsiz);
if(This->sector_size > MAX_SECTOR)
{
fprintf(stderr,"init %s: sector size too big\n", deviceName);
return NULL;
}
int i = log_2(This->sector_size);
if(i == 24)
{
fprintf(stderr, "init %s: sector size (%d) not a small power of two\n", deviceName, This->sector_size);
return NULL;
}
This->sectorShift = i;
This->sectorMask = This->sector_size - 1;
int cylinder_size = dev.heads * dev.sectors;
This->serialized = 0;
struct label_blk_t *labelBlock;
/*
* all numbers are in sectors, except num_clus
* (which is in clusters)
*/
int nhs = 0;
size_t tot_sectors = WORD_S(psect);
if(!tot_sectors)
{
tot_sectors = DWORD_S(bigsect);
nhs = DWORD_S(nhs);
}
else
nhs = WORD_S(nhs);
This->cluster_size = boot.boot.clsiz;
This->fat_start = WORD_S(nrsvsect);
This->fat_len = WORD_S(fatlen);
This->dir_len = WORD_S(dirents) * MDIR_SIZE / This->sector_size;
This->num_fat = boot.boot.nfat;
if (This->fat_len)
labelBlock = &boot.boot.ext.old.labelBlock;
else
labelBlock = &boot.boot.ext.fat32.labelBlock;
if (labelBlock->dos4 == 0x29)
{
This->serialized = 1;
This->serial_number = _DWORD(labelBlock->serial);
}
if (tot_sectors >= (maxSize >> This->sectorShift))
{
fprintf(stderr, "Big disks not supported on this architecture\n");
return NULL; // TODO: make caller check return code
}
int disk_size = cylinder_size;
if(disk_size > 256)
{
disk_size = dev.sectors;
if(dev.sectors % 2)
disk_size <<= 1;
}
if (disk_size % 2)
disk_size *= 2;
int blocksize = (!dev.blocksize || dev.blocksize < This->sector_size) ? This->sector_size : dev.blocksize;
if (disk_size)
This->Next = buf_init(This->Direct, 8 * disk_size * blocksize, disk_size * blocksize, This->sector_size);
else
This->Next = This->Direct;
if (This->Next == NULL)
{
perror("init: allocate buffer");
This->Next = This->Direct;
}
/* read the FAT sectors */
if(fat_read(This, &boot, dev.fat_bits, tot_sectors, dev.use_2m & 0x7f))
{
fprintf(stderr, "fs_init: Reading FAT failed.\n");
This->num_fat = 1;
free_stream(&This->Next);
free(This->Next);
return NULL;
}
/* Set the codepage */
This->cp = cp_open(dev.codepage);
if(This->cp == NULL)
{
fprintf(stderr, "fs_init: Setting code page failed.\n");
fs_free((struct Stream_t *)This);
free_stream(&This->Next);
free(This->Next);
return NULL;
}
return (struct Stream_t*) This;
}
int fs_close(struct Stream_t* Stream)
{
DeclareThis(struct Fs_t);
int rval = SimpleFileClose(This->Direct);
if (This->Next != This->Direct)
{
free_stream(&This->Next);
free(This->Next);
}
fs_free((struct Stream_t *)This);
free(This);
return rval;
}
int fsPreallocateClusters(struct Fs_t *Fs, long size)
{
if(size > 0 && getfreeMinClusters((struct Stream_t *)Fs, size) != 1)
return -1;
Fs->preallocatedClusters += size;
return 0;
}

View file

@ -1,30 +0,0 @@
/* Copyright 1996-2005,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_INIT_H
#define MTOOLS_INIT_H
struct Stream_t;
struct Fs_t;
struct Stream_t *fs_init(const char* deviceName, int mode);
struct Stream_t *GetFs(struct Stream_t *Fs);
int fs_close(struct Stream_t* Fs);
int fsPreallocateClusters(struct Fs_t *Fs, long);
#endif

View file

@ -1,57 +0,0 @@
/* Copyright 1999-2003,2006,2008,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "stream.h"
#include "fs.h"
#include "llong.h"
#include "mtools.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
const off_t max_off_t_32 = MAX_OFF_T_B(32); /* Directory */
const off_t max_off_t_seek = MAX_OFF_T_B(SEEK_BITS); /* SCSI */
static int fileTooBig(off_t off)
{
return (off & ~max_off_t_32) != 0;
}
off_t truncBytes32(off_t off)
{
if (fileTooBig(off))
{
fprintf(stderr, "Internal error, offset too big\n");
return off; // TODO: this used to be an exit(1)...
}
return (off_t) off;
}
off_t sectorsToBytes(struct Stream_t *Stream, off_t off)
{
DeclareThis(struct Fs_t);
return (off_t) off << This->sectorShift;
}
int mt_lseek(int fd, off_t where, int whence)
{
return lseek64(fd, where, whence) >= 0 ? 0 : -1;
}

View file

@ -1,39 +0,0 @@
/* Copyright 1999,2001-2004,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_LLONG_H
#define MTOOLS_LLONG_H
#include <stddef.h>
#include <sys/types.h>
#define min(a,b) ((a) < (b) ? (a) : (b))
#define MAX_OFF_T_B(bits) ((((off_t) 1 << min(bits-1, sizeof(off_t)*8 - 2)) -1) << 1 | 1)
#define SEEK_BITS 63
struct Stream_t;
extern const off_t max_off_t_32;
extern const off_t max_off_t_seek;
off_t truncBytes32(off_t off);
off_t sectorsToBytes(struct Stream_t *This, off_t off);
int mt_lseek(int fd, off_t where, int whence);
#endif

View file

@ -1,186 +0,0 @@
/* Copyright 1986-1992 Emmet P. Gray.
* Copyright 1996-1998,2001,2002,2008,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*
* Do shell-style pattern matching for '?', '\', '[..]', and '*' wildcards.
* Returns 1 if match, 0 if not.
*/
#include "mtools.h"
#include <wctype.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
static int casecmp(wchar_t a, wchar_t b)
{
return towupper(a) == towupper(b);
}
static int exactcmp(wchar_t a,wchar_t b)
{
return a == b;
}
static int parse_range(const wchar_t **p, const wchar_t *s, wchar_t *out, int (*compfn)(wchar_t a, wchar_t b))
{
wchar_t table[256];
int reverse;
int i;
if (**p == '^')
{
reverse = 1;
(*p)++;
}
else
reverse = 0;
for (i = 0; i < 256; i++)
table[i] = 0;
while (**p != ']')
{
if(!**p)
return 0;
if((*p)[1] == '-')
{
short first = **p;
(*p) += 2;
short last = (**p == ']') ? 256 : *((*p)++);
for(i = first; i <= last; i++)
table[i] = 1;
}
else
table[(int) *((*p)++)] = 1;
}
if(out)
*out = *s;
if(table[(int) *s])
return 1 ^ reverse;
if(compfn == exactcmp)
return reverse;
if(table[tolower(*s)])
{
if(out)
*out = tolower(*s);
return 1 ^ reverse;
}
if(table[toupper(*s)])
{
if(out)
*out = toupper(*s);
return 1 ^ reverse;
}
return reverse;
}
static int _match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case, int length, int (*compfn) (wchar_t a, wchar_t b))
{
for (; *p != '\0' && length; )
{
switch (*p)
{
case '?': /* match any one character */
if (*s == '\0')
return(0);
if(out)
*(out++) = *s;
break;
case '*': /* match everything */
while (*p == '*' && length)
{
p++;
length--;
}
/* search for next char in pattern */
while(*s)
{
if(_match(s, p, out, Case, length,
compfn))
return 1;
if(out)
*out++ = *s;
s++;
}
continue;
case '[': /* match range of characters */
p++;
length--;
if(!parse_range(&p, s, out++, compfn))
return 0;
break;
case '\\': /* Literal match with next character */
p++;
length--;
/* fall thru */
default:
if (!compfn(*s,*p))
return(0);
if(out)
*(out++) = *p;
break;
}
p++;
length--;
s++;
}
if(out)
*out = '\0';
/* string ended prematurely ? */
return *s != '\0' ? 0 : 1;
}
int match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case, int length)
{
int (*compfn)(wchar_t a, wchar_t b);
if(Case)
compfn = casecmp;
else
/*compfn = exactcmp;*/
compfn = casecmp;
return _match(s, p, out, Case, length, compfn);
}

View file

@ -1,24 +0,0 @@
/* Copyright 1996-2005,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_MATCH_H
#define MTOOLS_MATCH_H
int match(const wchar_t *, const wchar_t *, wchar_t *, int, int);
#endif

View file

@ -1,197 +0,0 @@
/* Copyright 1986-1992 Emmet P. Gray.
* Copyright 1996-1998,2000-2003,2006,2007,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MTOOLS_MSDOS_H
#define MTOOLS_MSDOS_H
#define MAX_SECTOR 8192 /* largest sector size */
#define MDIR_SIZE 32 /* MSDOS directory entry size in bytes*/
#define MAX_CLUSTER 8192 /* largest cluster size */
#define MAX_DIR_SECS 64 /* largest directory (in sectors) */
#define MSECTOR_SIZE msector_size
#define _WORD(x) ((unsigned short)((unsigned char)(x)[0] + (((unsigned char)(x)[1]) << 8)))
#define _DWORD(x) ((unsigned int)(_WORD(x) + (_WORD((x)+2) << 16)))
#define DELMARK ((char) 0xe5)
#define EXTCASE 0x10
#define BASECASE 0x8
#define MAX16 0xffff
#define MAX32 0xffffffff
#define MAX_SIZE 0x7fffffff
#define FILE_SIZE(dir) (_DWORD((dir)->size))
#define START(dir) (_WORD((dir)->start))
#define STARTHI(dir) (_WORD((dir)->startHi))
/* ASSUMPTION: long is at least 32 bits */
static inline void set_dword(unsigned char *data, unsigned long value)
{
data[3] = (value >> 24) & 0xff;
data[2] = (value >> 16) & 0xff;
data[1] = (value >> 8) & 0xff;
data[0] = (value >> 0) & 0xff;
}
/* ASSUMPTION: short is at least 16 bits */
static inline void set_word(unsigned char *data, unsigned short value)
{
data[1] = (value >> 8) & 0xff;
data[0] = (value >> 0) & 0xff;
}
struct InfoSector_t
{
unsigned char signature1[4];
unsigned char filler1[0x1e0];
unsigned char signature2[4];
unsigned char count[4];
unsigned char pos[4];
unsigned char filler2[14];
unsigned char signature3[2];
};
#define INFOSECT_SIGNATURE1 0x41615252
#define INFOSECT_SIGNATURE2 0x61417272
struct label_blk_t
{
unsigned char physdrive; /* 36 physical drive ? */
unsigned char reserved; /* 37 reserved */
unsigned char dos4; /* 38 dos > 4.0 diskette */
unsigned char serial[4]; /* 39 serial number */
char label[11]; /* 43 disk label */
char fat_type[8]; /* 54 FAT type */
};
/* FAT32 specific info in the bootsector */
struct fat32_t
{
unsigned char bigFat[4]; /* 36 nb of sectors per FAT */
unsigned char extFlags[2]; /* 40 extension flags */
unsigned char fsVersion[2]; /* 42 ? */
unsigned char rootCluster[4]; /* 44 start cluster of root dir */
unsigned char infoSector[2]; /* 48 changeable global info */
unsigned char backupBoot[2]; /* 50 back up boot sector */
unsigned char reserved[6]; /* 52 ? */
unsigned char reserved2[6]; /* 52 ? */
struct label_blk_t labelBlock;
}; /* ends at 58 */
struct oldboot_t
{
struct label_blk_t labelBlock;
unsigned char res_2m; /* 62 reserved by 2M */
unsigned char CheckSum; /* 63 2M checksum (not used) */
unsigned char fmt_2mf; /* 64 2MF format version */
unsigned char wt; /* 65 1 if write track after format */
unsigned char rate_0; /* 66 data transfer rate on track 0 */
unsigned char rate_any; /* 67 data transfer rate on track<>0 */
unsigned char BootP[2]; /* 68 offset to boot program */
unsigned char Infp0[2]; /* 70 T1: information for track 0 */
unsigned char InfpX[2]; /* 72 T2: information for track<>0 */
unsigned char InfTm[2]; /* 74 T3: track sectors size table */
unsigned char DateF[2]; /* 76 Format date */
unsigned char TimeF[2]; /* 78 Format time */
unsigned char junk[1024 - 80]; /* 80 remaining data */
};
struct bootsector_s
{
unsigned char jump[3]; /* 0 Jump to boot code */
char banner[8]; /* 3 OEM name & version */
unsigned char secsiz[2]; /* 11 Bytes per sector hopefully 512 */
unsigned char clsiz; /* 13 Cluster size in sectors */
unsigned char nrsvsect[2]; /* 14 Number of reserved (boot) sectors */
unsigned char nfat; /* 16 Number of FAT tables hopefully 2 */
unsigned char dirents[2]; /* 17 Number of directory slots */
unsigned char psect[2]; /* 19 Total sectors on disk */
unsigned char descr; /* 21 Media descriptor=first byte of FAT */
unsigned char fatlen[2]; /* 22 Sectors in FAT */
unsigned char nsect[2]; /* 24 Sectors/track */
unsigned char nheads[2]; /* 26 Heads */
unsigned char nhs[4]; /* 28 number of hidden sectors */
unsigned char bigsect[4]; /* 32 big total sectors */
union
{
struct fat32_t fat32;
struct oldboot_t old;
} ext;
};
#define MAX_BOOT 4096
union bootsector
{
unsigned char bytes[MAX_BOOT];
char characters[MAX_BOOT];
struct bootsector_s boot;
};
#define CHAR(x) (boot->x[0])
#define WORD(x) (_WORD(boot->boot.x))
#define DWORD(x) (_DWORD(boot->boot.x))
#define WORD_S(x) (_WORD(boot.boot.x))
#define DWORD_S(x) (_DWORD(boot.boot.x))
#define OFFSET(x) (((char *) (boot->x)) - ((char *)(boot->jump)))
/* max FAT12/FAT16 sizes, according to
http://www.microsoft.com/hwdev/download/hardware/fatgen103.pdf
interestingly enough, another Microsoft document
[http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b67321]
gives different values, but the first seems to be more sure about
itself, so we believe that one ;-)
*/
#define FAT12 4085 /* max. number of clusters described by a 12 bit FAT */
#define FAT16 65525 /* max number of clusters for a 16 bit FAT */
#define ATTR_ARCHIVE 0x20
#define ATTR_DIR 0x10
#define ATTR_LABEL 0x8
#define ATTR_SYSTEM 0x4
#define ATTR_HIDDEN 0x2
#define ATTR_READONLY 0x1
#define HAS_BIT(entry,x) ((entry)->dir.attr & (x))
#define IS_ARCHIVE(entry) (HAS_BIT((entry),ATTR_ARCHIVE))
#define IS_DIR(entry) (HAS_BIT((entry),ATTR_DIR))
#define IS_LABEL(entry) (HAS_BIT((entry),ATTR_LABEL))
#define IS_SYSTEM(entry) (HAS_BIT((entry),ATTR_SYSTEM))
#define IS_HIDDEN(entry) (HAS_BIT((entry),ATTR_HIDDEN))
#define IS_READONLY(entry) (HAS_BIT((entry),ATTR_READONLY))
#define MAX_BYTES_PER_CLUSTER (32*1024)
/* Experimentally, it turns out that DOS only accepts cluster sizes
* which are powers of two, and less than 128 sectors (else it gets a
* divide overflow) */
#define MT_READ 1
#define MT_WRITE 2
#endif

View file

@ -1,36 +0,0 @@
/* Copyright 1996-2005,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_MTOOLS_H
#define MTOOLS_MTOOLS_H
#define UNUSED(x) x __attribute__ ((unused))
#define New(type) ((type*)(calloc(1,sizeof(type))))
#define Grow(adr,n,type) ((type*)(realloc((char *)adr,n*sizeof(type))))
#define NewArray(size,type) ((type*)(calloc((size),sizeof(type))))
#define maximize(target, max) do { \
if(max < 0) \
{ \
if(target > 0) \
target = 0; \
} \
else if(target > max) \
target = max; \
} while(0)
#endif

View file

@ -1,55 +0,0 @@
/* Copyright 1996-1998,2000-2002,2008,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_NAMECLASH_H
#define MTOOLS_NAMECLASH_H
struct dos_name_t;
struct doscp_t;
typedef enum clash_action
{
NAMEMATCH_SUCCESS = 0,
NAMEMATCH_NONE,
NAMEMATCH_SKIP,
NAMEMATCH_ERROR,
NAMEMATCH_GREW
} clash_action;
/* clash handling structure */
struct ClashHandling_t
{
clash_action action[2];
clash_action namematch_default[2];
int nowarn; /* Don't ask, just do default action if name collision*/
int got_slots;
int mod_time;
char *myname;
unsigned char *dosname;
int single;
int use_longname;
int ignore_entry;
int source; /* to prevent the source from overwriting itself */
int source_entry; /* to account for the space freed up by the original name */
void (*name_converter)(struct doscp_t *cp, const char *filename, int *mangled, struct dos_name_t *ans);
};
#endif

View file

@ -1,49 +0,0 @@
/* Copyright 1997,1998,2001-2003,2006,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_PARTITION_H
#define MTOOLS_PARTITION_H
struct hsc
{
unsigned char byte0;
unsigned char head; /* starting head */
unsigned char sector; /* starting sector */
unsigned char cyl; /* starting cylinder */
};
#define head(x) ((unsigned int)((x).head))
#define sector(x) ((unsigned int)((x).sector & 0x3f))
#define cyl(x) ((unsigned int)((x).cyl | (((x).sector & 0xc0)<<2)))
#define BEGIN(p) _DWORD((p).start_sect)
#define END(p) (_DWORD((p).start_sect)+(_DWORD((p).nr_sects)))
#define boot_ind start.byte0
#define sys_ind end.byte0
struct partition
{
struct hsc start;
struct hsc end;
unsigned char start_sect[4]; /* starting sector counting from 0 */
unsigned char nr_sects[4]; /* nr of sectors in partition */
};
#endif

View file

@ -1,426 +0,0 @@
/* Copyright 1995-2007,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*
* Io to a plain file or device
*
* written by:
*
* Alain L. Knaff
* alain@knaff.lu
*
*/
#include "stream.h"
#include "mtools.h"
#include "msdos.h"
#include "plain_io.h"
#include "partition.h"
#include "llong.h"
#include "force_io.h"
#include "devices.h"
#include <sys/file.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
struct SimpleFile_t
{
struct Class_t *Class;
int refs;
struct Stream_t *Next;
struct Stream_t *Buffer;
struct stat64 statbuf;
int fd;
off_t offset;
off_t lastwhere;
int seekable;
int privileged;
int scsi_sector_size;
void *extra_data; /* extra system dependant information for scsi */
int swap; /* do the word swapping */
};
static int lock_dev(int fd, int mode)
{
if (flock(fd, (mode ? LOCK_EX : LOCK_SH) | LOCK_NB) < 0)
return errno == EINVAL || errno == EOPNOTSUPP ? 0 : 1;
return 0;
}
typedef int (*iofn) (int, char *, int);
static void swap_buffer(char *buf, size_t len)
{
unsigned int i;
for (i = 0; i<len; i+=2)
{
char temp = buf[i];
buf[i] = buf[i+1];
buf[i+1] = temp;
}
}
static int file_io(struct Stream_t *Stream, char *buf, off_t where, int len, iofn io)
{
DeclareThis(struct SimpleFile_t);
where += This->offset;
if (This->seekable && where != This->lastwhere )
{
if(mt_lseek( This->fd, where, SEEK_SET) < 0 )
{
perror("seek");
This->lastwhere = (off_t) -1;
return -1;
}
}
int ret = io(This->fd, buf, len);
if (ret == -1 )
{
perror("plain_io");
This->lastwhere = (off_t) -1;
return -1;
}
This->lastwhere = where + ret;
return ret;
}
static int file_read(struct Stream_t *Stream, char *buf, off_t where, size_t len)
{
DeclareThis(struct SimpleFile_t);
int result = file_io(Stream, buf, where, len, (iofn) read);
if (This->swap)
swap_buffer(buf, len);
return result;
}
static int file_write(struct Stream_t *Stream, char *buf, off_t where, size_t len)
{
DeclareThis(struct SimpleFile_t);
if (!This->swap)
return file_io(Stream, buf, where, len, (iofn) write);
else
{
char* swapping = malloc(len);
memcpy(swapping, buf, len);
swap_buffer(swapping, len);
int result = file_io(Stream, swapping, where, len, (iofn) write);
free(swapping);
return result;
}
}
static int file_flush(struct Stream_t UNUSED(*Stream))
{
return 0;
}
static int file_free(struct Stream_t *Stream)
{
DeclareThis(struct SimpleFile_t);
return (This->fd > 2) ? close(This->fd) : 0;
}
static int file_geom(struct Stream_t *Stream, struct device *dev, struct device *orig_dev, int media, union bootsector *boot)
{
DeclareThis(struct SimpleFile_t);
dev->ssize = 2; /* allow for init_geom to change it */
dev->use_2m = 0x80; /* disable 2m mode to begin */
if(media == 0xf0 || media >= 0x100)
{
dev->heads = WORD(nheads);
dev->sectors = WORD(nsect);
size_t tot_sectors = DWORD(bigsect);
if (WORD(psect))
tot_sectors = WORD(psect);
int sect_per_track = dev->heads * dev->sectors;
if(sect_per_track == 0)
{
/* add some fake values if sect_per_track is
* zero. Indeed, some atari disks lack the
* geometry values (i.e. have zeroes in their
* place). In order to avoid division by zero
* errors later on, plug 1 everywhere
*/
dev->heads = 1;
dev->sectors = 1;
sect_per_track = 1;
}
tot_sectors += sect_per_track - 1; /* round size up */
dev->tracks = tot_sectors / sect_per_track;
}
else
{
fprintf(stderr,"Unknown media type\n");
return -1; // TODO: make sure this is interpreted as invalid return code
}
int sectors = dev->sectors;
dev->sectors = dev->sectors * WORD(secsiz) / 512;
int ret = init_geom(This->fd,dev, orig_dev, &This->statbuf);
dev->sectors = sectors;
return ret;
}
static int file_data(struct Stream_t *Stream, time_t *date, size_t *size,
int *type, int *address)
{
DeclareThis(struct SimpleFile_t);
if(date)
*date = This->statbuf.st_mtime;
if(size)
*size = This->statbuf.st_size;
if(type)
*type = S_ISDIR(This->statbuf.st_mode);
if(address)
*address = 0;
return 0;
}
static struct Class_t SimpleFileClass =
{
file_read,
file_write,
file_flush,
file_free,
file_geom,
file_data,
0, /* pre_allocate */
0
};
struct Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev,
const char *name, int mode, char *errmsg,
int mode2, int locked, size_t *maxSize)
{
struct SimpleFile_t *This;
This = New(struct SimpleFile_t);
if (!This)
{
fprintf(stderr, "%s %d: Allocation memory for simple file failed.\n", __FILE__, __LINE__);
return 0;
}
This->scsi_sector_size = 512;
This->seekable = 1;
This->Class = &SimpleFileClass;
if (!name || strcmp(name,"-") == 0)
{
This->fd = mode == O_RDONLY ? 0 : 1;
This->seekable = 0;
This->refs = 1;
This->Next = 0;
This->Buffer = 0;
if (fstat64(This->fd, &This->statbuf) < 0)
{
free(This);
if(errmsg)
snprintf(errmsg,199,"Can't stat -: %s", strerror(errno));
return NULL;
}
return (struct Stream_t *) This;
}
if(dev)
mode |= dev->mode;
This->fd = open(name, mode | O_LARGEFILE, 0666);
if (This->fd < 0)
{
free(This);
if(errmsg)
snprintf(errmsg, 199, "Can't open %s: %s", name, strerror(errno));
return NULL;
}
if (fstat64(This->fd, &This->statbuf) < 0)
{
free(This);
if(errmsg)
snprintf(errmsg, 199,"Can't stat %s: %s", name, strerror(errno));
return NULL;
}
/* lock the device on writes */
if (locked && lock_dev(This->fd, mode == O_RDWR))
{
if(errmsg)
snprintf(errmsg, 199, "plain floppy: device \"%s\" busy (%s):", dev ? dev->name : "unknown", strerror(errno));
close(This->fd);
free(This);
return NULL;
}
/* set default parameters, if needed */
if (dev)
{
if (dev->tracks && init_geom(This->fd, dev, orig_dev, &This->statbuf))
{
close(This->fd);
free(This);
if(errmsg)
sprintf(errmsg,"init: set default params");
return NULL;
}
This->offset = (off_t) dev->offset;
}
else
This->offset = 0;
This->refs = 1;
This->Next = 0;
This->Buffer = 0;
if(maxSize)
{
*maxSize = max_off_t_seek;
if(This->offset > 0 && (size_t) This->offset > *maxSize)
{
close(This->fd);
free(This);
if(errmsg)
sprintf(errmsg,"init: Big disks not supported");
return NULL;
}
*maxSize -= This->offset;
}
/* partitioned drive */
This->swap = 0;
if(!(mode2 & NO_OFFSET) && dev && dev->partition > 4)
fprintf(stderr, "Invalid partition %d (must be between 0 and 4), ignoring it\n", dev->partition);
while(!(mode2 & NO_OFFSET) && dev && dev->partition && dev->partition <= 4)
{
unsigned char buf[2048];
struct partition *partTable = (struct partition *)(buf+ 0x1ae);
size_t partOff;
/* read the first sector, or part of it */
if (force_read((struct Stream_t *)This, (char*) buf, 0, 512) != 512)
break;
if( _WORD(buf + 510) != 0xaa55)
break;
partOff = BEGIN(partTable[dev->partition]);
if (maxSize)
{
if (partOff > *maxSize >> 9)
{
close(This->fd);
free(This);
if(errmsg)
sprintf(errmsg,"init: Big disks not supported");
return NULL;
}
*maxSize -= (off_t) partOff << 9;
}
This->offset += (off_t) partOff << 9;
if(!partTable[dev->partition].sys_ind)
{
if(errmsg)
sprintf(errmsg, "init: non-existent partition");
close(This->fd);
free(This);
return NULL;
}
if(!dev->tracks)
{
dev->heads = head(partTable[dev->partition].end) + 1;
dev->sectors = sector(partTable[dev->partition].end);
dev->tracks = cyl(partTable[dev->partition].end) - cyl(partTable[dev->partition].start) + 1;
}
dev->hidden = dev->sectors*head(partTable[dev->partition].start) + sector(partTable[dev->partition].start) - 1;
break;
}
This->lastwhere = -This->offset;
/* provoke a seek on those devices that don't start on a partition
* boundary */
return (struct Stream_t *) This;
}
int SimpleFileClose(struct Stream_t* Stream)
{
DeclareThis(struct SimpleFile_t);
return close(This->fd);
}

View file

@ -1,33 +0,0 @@
/* Copyright 1996,1997,1999,2001,2002,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_PLAINIO_H
#define MTOOLS_PLAINIO_H
#include <stddef.h>
struct device;
struct Stream_t;
#define NO_PRIV 1
#define NO_OFFSET 2
struct Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev, const char *name, int mode, char *errmsg, int mode2, int locked, size_t *maxSize);
int SimpleFileClose(struct Stream_t* Stream);
#endif

View file

@ -1,95 +0,0 @@
/* Copyright 1996,1997,1999,2001,2002,2008,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "msdos.h"
#include "stream.h"
#include <stdlib.h>
int flush_stream(struct Stream_t *Stream)
{
int ret = 0;
if(Stream->Class->flush)
ret |= Stream->Class->flush(Stream);
if(Stream->Next)
ret |= flush_stream(Stream->Next);
return ret;
}
struct Stream_t *copy_stream(struct Stream_t *Stream)
{
if(Stream)
Stream->refs++;
return Stream;
}
int free_stream(struct Stream_t **Stream)
{
if(!*Stream)
return -1;
int ret = 0;
if(! --(*Stream)->refs)
{
if((*Stream)->Class->flush)
ret |= (*Stream)->Class->flush(*Stream);
if((*Stream)->Class->freeFunc)
ret |= (*Stream)->Class->freeFunc(*Stream);
if((*Stream)->Next)
ret |= free_stream(&(*Stream)->Next);
free(*Stream);
}
else if ((*Stream)->Next)
ret |= flush_stream((*Stream)->Next);
*Stream = NULL;
return ret;
}
#define GET_DATA(stream, date, size, type, address) \
(stream)->Class->get_data( (stream), (date), (size), (type), (address) )
int get_data_pass_through(struct Stream_t *Stream, time_t *date, size_t *size, int *type, int *address)
{
return GET_DATA(Stream->Next, date, size, type, address);
}
int read_pass_through(struct Stream_t *Stream, char *buf, off_t start, size_t len)
{
return READS(Stream->Next, buf, start, len);
}
int write_pass_through(struct Stream_t *Stream, char *buf, off_t start, size_t len)
{
return WRITES(Stream->Next, buf, start, len);
}
struct doscp_t *get_dosConvert_pass_through(struct Stream_t *Stream)
{
return GET_DOSCONVERT(Stream->Next);
}

View file

@ -1,80 +0,0 @@
/* Copyright 1996-1999,2001,2002,2005,2006,2008,2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_STREAM_H
#define MTOOLS_STREAM_H
#include <time.h>
#include <sys/types.h>
struct doscp_t;
union bootsector;
struct device;
struct Stream_t
{
struct Class_t *Class;
int refs;
struct Stream_t *Next;
struct Stream_t *Buffer;
};
struct doscp_t *get_dosConvert_pass_through(struct Stream_t *Stream);
struct Class_t
{
int (*read)(struct Stream_t *, char *, off_t, size_t);
int (*write)(struct Stream_t *, char *, off_t, size_t);
int (*flush)(struct Stream_t *);
int (*freeFunc)(struct Stream_t *);
int (*set_geom)(struct Stream_t *, struct device *, struct device *, int media, union bootsector *);
int (*get_data)(struct Stream_t *, time_t *, size_t *, int *, int *);
int (*pre_allocate)(struct Stream_t *, size_t);
struct doscp_t *(*get_dosConvert)(struct Stream_t *);
};
#define READS(stream, buf, address, size) \
((stream)->Class->read)( (stream), (char *) (buf), (address), (size) )
#define WRITES(stream, buf, address, size) \
((stream)->Class->write)( (stream), (char *) (buf), (address), (size) )
#define SET_GEOM(stream, dev, orig_dev, media, boot) \
(stream)->Class->set_geom( (stream), (dev), (orig_dev), (media), (boot) )
#define GET_DATA(stream, date, size, type, address) \
(stream)->Class->get_data( (stream), (date), (size), (type), (address) )
#define PRE_ALLOCATE(stream, size) \
(stream)->Class->pre_allocate((stream), (size))
#define GET_DOSCONVERT(stream) \
(stream)->Class->get_dosConvert((stream))
int flush_stream(struct Stream_t *Stream);
struct Stream_t *copy_stream(struct Stream_t *Stream);
int free_stream(struct Stream_t **Stream);
#define DeclareThis(x) x *This = (x *) Stream
int get_data_pass_through(struct Stream_t *Stream, time_t *date, size_t *size, int *type, int *address);
int read_pass_through(struct Stream_t *Stream, char *buf, off_t start, size_t len);
int write_pass_through(struct Stream_t *Stream, char *buf, off_t start, size_t len);
#endif

View file

@ -1,714 +0,0 @@
/* Copyright 1995 David C. Niemi
* Copyright 1996-2003,2005,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*
* vfat.c
*
* Miscellaneous VFAT-related functions
*/
#include "msdos.h"
#include "mtools.h"
#include "vfat.h"
#include "file.h"
#include "dirCache.h"
#include "file_name.h"
#include "match.h"
#include "directory.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
static int unicode_read(struct unicode_char *in, wchar_t *out, int num)
{
wchar_t *end_out = out + num;
while(out < end_out)
{
*out = in->lchar | ((in->uchar) << 8);
++out;
++in;
}
return num;
}
static void clear_vfat(struct vfat_state *v)
{
v->subentries = 0;
v->status = 0;
v->present = 0;
}
/* sum_shortname
*
* Calculate the checksum that results from the short name in *dir.
*
* The sum is formed by circularly right-shifting the previous sum
* and adding in each character, from left to right, padding both
* the name and extension to maximum length with spaces and skipping
* the "." (hence always summing exactly 11 characters).
*
* This exact algorithm is required in order to remain compatible
* with Microsoft Windows-95 and Microsoft Windows NT 3.5.
* Thanks to Jeffrey Richter of Microsoft Systems Journal for
* pointing me to the correct algorithm.
*
* David C. Niemi (niemi@tuxers.net) 95.01.19
*/
static unsigned char sum_shortname(const struct dos_name_t *dn)
{
unsigned char sum = 0;
const char *name = dn->base;
const char *end = name + 11;
for (sum = 0; name<end; ++name)
sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + *name;
return sum;
}
/* check_vfat
*
* Inspect a directory and any associated VSEs.
* Return 1 if the VSEs comprise a valid long file name,
* 0 if not.
*/
static void check_vfat(struct vfat_state *v, struct directory *dir)
{
struct dos_name_t dn;
if (! v->subentries)
return;
memcpy(dn.base, (char *)dir->name, 8);
memcpy(dn.ext, (char *)dir->ext, 3);
if (v->sum != sum_shortname(&dn))
return;
if ((v->status & ((1 << v->subentries) - 1)) != (1 << v->subentries) - 1)
return; /* missing entries */
/* zero out byte following last entry, for good measure */
v->name[VSE_NAMELEN * v->subentries] = 0;
v->present = 1;
}
int clear_vses(struct Stream_t *Dir, int entrySlot, size_t last)
{
struct dirCache_t *cache = allocDirCache(Dir, last);
int error;
if (!cache)
return -1; // TODO: check return code
struct direntry_t entry;
entry.Dir = Dir;
entry.entry = entrySlot;
addFreeEntry(cache, entry.entry, last);
for (; entry.entry < (signed int) last; ++entry.entry)
{
dir_read(&entry, &error);
if(error)
return error;
if(!entry.dir.name[0] || entry.dir.name[0] == DELMARK)
break;
entry.dir.name[0] = DELMARK;
if (entry.dir.attr == 0xf)
entry.dir.attr = '\0';
low_level_dir_write(&entry);
}
return 0;
}
int write_vfat(struct Stream_t *Dir, struct dos_name_t *shortname, char *longname, int start, struct direntry_t *mainEntry)
{
struct vfat_subentry *vse;
int vse_id;
int num_vses;
wchar_t *c;
struct direntry_t entry;
struct dirCache_t *cache;
wchar_t unixyName[13];
struct doscp_t *cp = GET_DOSCONVERT(Dir);
wchar_t wlongname[MAX_VNAMELEN+1];
int wlen;
if(longname)
{
entry.Dir = Dir;
vse = (struct vfat_subentry *) &entry.dir;
/* Fill in invariant part of vse */
vse->attribute = 0x0f;
vse->hash1 = vse->sector_l = vse->sector_u = 0;
vse->sum = sum_shortname(shortname);
wlen = native_to_wchar(longname, wlongname, MAX_VNAMELEN + 1, 0, 0);
num_vses = (wlen + VSE_NAMELEN - 1) / VSE_NAMELEN;
for (vse_id = num_vses; vse_id; --vse_id)
{
int end = 0;
c = wlongname + (vse_id - 1) * VSE_NAMELEN;
c += unicode_write(c, vse->text1, VSE1SIZE, &end);
c += unicode_write(c, vse->text2, VSE2SIZE, &end);
c += unicode_write(c, vse->text3, VSE3SIZE, &end);
vse->id = (vse_id == num_vses) ? (vse_id | VSE_LAST) : vse_id;
entry.entry = start + num_vses - vse_id;
low_level_dir_write(&entry);
}
}
else
{
num_vses = 0;
wlongname[0]='\0';
}
cache = allocDirCache(Dir, start + num_vses + 1);
if(!cache)
return -1; // TODO: check return code
unix_name(cp, shortname->base, shortname->ext, 0, unixyName);
addUsedEntry(cache, start, start + num_vses + 1, wlongname, unixyName, &mainEntry->dir);
low_level_dir_write(mainEntry);
return start + num_vses;
}
int dir_write(struct direntry_t *entry)
{
if (entry->entry == -3)
{
fprintf(stderr, "Attempt to write root directory pointer\n");
return -2; // TODO: make caller check return code
}
struct dirCache_t *cache = allocDirCache(entry->Dir, entry->entry + 1);
if (!cache)
{
fprintf(stderr, "Out of memory error in dir_write\n");
return -1; // TODO: make caller check return code
}
struct dirCacheEntry_t *dce = cache->entries[entry->entry];
if (dce)
{
if(entry->dir.name[0] == DELMARK)
addFreeEntry(cache, dce->beginSlot, dce->endSlot);
else
dce->dir = entry->dir;
}
low_level_dir_write(entry);
return 0;
}
/*
* The following function translates a series of vfat_subentries into
* data suitable for a dircache entry
*/
static void parse_vses(struct direntry_t *entry, struct vfat_state *v)
{
struct vfat_subentry *vse = (struct vfat_subentry *) &entry->dir;
unsigned char id = vse->id & VSE_MASK;
unsigned char last_flag = (vse->id & VSE_LAST);
if (id > MAX_VFAT_SUBENTRIES)
{
fprintf(stderr, "parse_vses: invalid VSE ID %d at %d.\n", id, entry->entry);
return;
}
/* 950819: This code enforced finding the VSEs in order. Well, Win95
* likes to write them in *reverse* order for some bizarre reason! So
* we pretty much have to tolerate them coming in any possible order.
* So skip this check, we'll do without it (What does this do, Alain?).
*
* 950820: Totally rearranged code to tolerate any order but to warn if
* they are not in reverse order like Win95 uses.
*
* 950909: Tolerate any order. We recognize new chains by mismatching
* checksums. In the event that the checksums match, new entries silently
* overwrite old entries of the same id. This should accept all valid
* entries, but may fail to reject invalid entries in some rare cases.
*/
/* bad checksum, begin new chain */
if(v->sum != vse->sum)
{
clear_vfat(v);
v->sum = vse->sum;
}
v->status |= 1 << (id-1);
if(last_flag)
v->subentries = id;
wchar_t* c = &(v->name[VSE_NAMELEN * (id-1)]);
c += unicode_read(vse->text1, c, VSE1SIZE);
c += unicode_read(vse->text2, c, VSE2SIZE);
c += unicode_read(vse->text3, c, VSE3SIZE);
if (last_flag)
*c = '\0'; /* Null terminate long name */
}
static struct dirCacheEntry_t *vfat_lookup_loop_common(struct doscp_t *cp,
struct direntry_t *direntry,
struct dirCache_t *cache,
int lookForFreeSpace,
int *io_error)
{
int initpos = direntry->entry + 1;
struct vfat_state vfat;
/* not yet cached */
*io_error = 0;
clear_vfat(&vfat);
while(1)
{
++direntry->entry;
int error;
if(!dir_read(direntry, &error))
{
if(error)
{
*io_error = error;
return NULL;
}
addFreeEntry(cache, initpos, direntry->entry);
return addEndEntry(cache, direntry->entry);
}
if (direntry->dir.name[0] == '\0')
{
/* the end of the directory */
if(lookForFreeSpace)
continue;
return addEndEntry(cache, direntry->entry);
}
if(direntry->dir.name[0] != DELMARK && direntry->dir.attr == 0x0f)
parse_vses(direntry, &vfat);
else
/* the main entry */
break;
}
/* If we get here, it's a short name FAT entry, maybe erased.
* thus we should make sure that the vfat structure will be
* cleared before the next loop run */
/* deleted file */
if (direntry->dir.name[0] == DELMARK)
return addFreeEntry(cache, initpos, direntry->entry + 1);
check_vfat(&vfat, &direntry->dir);
if(!vfat.present)
vfat.subentries = 0;
/* mark space between last entry and this one as free */
addFreeEntry(cache, initpos, direntry->entry - vfat.subentries);
wchar_t newfile[13];
if (direntry->dir.attr & 0x8)
{
/* Read entry as a label */
wchar_t *ptr = newfile;
ptr += dos_to_wchar(cp, direntry->dir.name, ptr, 8);
ptr += dos_to_wchar(cp, direntry->dir.ext, ptr, 3);
*ptr = '\0';
}
else
unix_name(cp, direntry->dir.name, direntry->dir.ext, direntry->dir.Case, newfile);
wchar_t* longname = vfat.present ? vfat.name : 0;
return addUsedEntry(cache, direntry->entry - vfat.subentries, direntry->entry + 1, longname, newfile, &direntry->dir);
}
static struct dirCacheEntry_t *vfat_lookup_loop_for_read(struct doscp_t *cp, struct direntry_t *direntry, struct dirCache_t *cache, int *io_error)
{
*io_error = 0;
struct dirCacheEntry_t *dce = cache->entries[direntry->entry + 1];
if(dce)
{
direntry->entry = dce->endSlot - 1;
return dce;
}
else
return vfat_lookup_loop_common(cp, direntry, cache, 0, io_error);
}
typedef enum result_t {
RES_NOMATCH,
RES_MATCH,
RES_END,
RES_ERROR
} result_t;
/*
* 0 does not match
* 1 matches
* 2 end
*/
static result_t checkNameForMatch(struct direntry_t *direntry,
struct dirCacheEntry_t *dce,
const wchar_t *filename,
int length,
int flags)
{
switch(dce->type)
{
case DCET_FREE:
return RES_NOMATCH;
case DCET_END:
return RES_END;
case DCET_USED:
break;
default:
fprintf(stderr, "Unexpected entry type %d\n", dce->type);
return RES_ERROR;
}
direntry->dir = dce->dir;
/* make sure the entry is of an accepted type */
if ((direntry->dir.attr & 0x8) && !(flags & ACCEPT_LABEL))
return RES_NOMATCH;
/*---------- multiple files ----------*/
if (!((flags & MATCH_ANY) ||
(dce->longName &&
match(dce->longName, filename, direntry->name, 0, length)) ||
match(dce->shortName, filename, direntry->name, 1, length)))
return RES_NOMATCH;
/* entry of non-requested type, has to come after name
* checking because of clash handling */
if(IS_DIR(direntry) && !(flags & ACCEPT_DIR)) {
if(!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG))) {
char tmp[4*13+1];
wchar_to_native(dce->shortName,tmp,13);
fprintf(stderr, "Skipping \"%s\", is a directory\n",
tmp);
}
return RES_NOMATCH;
}
if (!(direntry->dir.attr & (ATTR_LABEL | ATTR_DIR)) && !(flags & ACCEPT_PLAIN))
{
if (!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG)))
{
char tmp[4*13+1];
wchar_to_native(dce->shortName,tmp,13);
fprintf(stderr, "Skipping \"%s\", is not a directory\n", tmp);
}
return RES_NOMATCH;
}
return RES_MATCH;
}
/*
* vfat_lookup looks for filenames in directory dir.
* if a name if found, it is returned in outname
* if applicable, the file is opened and its stream is returned in File
*/
int vfat_lookup(struct direntry_t *direntry, const char *filename, int length, int flags, char *shortname, char *longname)
{
wchar_t wfilename[MAX_VNAMELEN+1];
wchar_t *wfilenamep = wfilename;
if(length == -1 && filename)
length = strlen(filename);
if(filename != NULL)
length = native_to_wchar(filename, wfilename, MAX_VNAMELEN, filename+length, 0);
else
{
wfilenamep = NULL;
length = 0;
}
if (direntry->entry == -2)
return -1;
struct dirCache_t *cache = allocDirCache(direntry->Dir, direntry->entry+1);
if(!cache)
{
fprintf(stderr, "Out of memory error in vfat_lookup [0]\n");
return -2; // TODO: make caller check return code
}
struct dirCacheEntry_t *dce = NULL;
result_t result;
struct doscp_t *cp = GET_DOSCONVERT(direntry->Dir);
do
{
int io_error;
dce = vfat_lookup_loop_for_read(cp, direntry, cache, &io_error);
if(!dce)
{
if (io_error)
return -2;
fprintf(stderr, "Out of memory error in vfat_lookup\n");
return -2;
}
result = checkNameForMatch(direntry, dce, wfilename, length, flags);
} while(result == RES_NOMATCH);
if(result == RES_MATCH)
{
if(longname)
{
if(dce->longName)
wchar_to_native(dce->longName, longname, MAX_VNAMELEN);
else
*longname ='\0';
}
if(shortname)
wchar_to_native(dce->shortName, shortname, 12);
direntry->beginSlot = dce->beginSlot;
direntry->endSlot = dce->endSlot-1;
return 0; /* file found */
}
direntry->entry = -2;
return -1; /* no file found */
}
static struct dirCacheEntry_t *vfat_lookup_loop_for_insert(struct doscp_t *cp,
struct direntry_t *direntry,
int initpos,
struct dirCache_t *cache)
{
struct dirCacheEntry_t *dce = cache->entries[initpos];
int io_error;
if(dce && dce->type != DCET_END)
return dce;
direntry->entry = initpos - 1;
dce = vfat_lookup_loop_common(cp, direntry, cache, 1, &io_error);
if(!dce)
{
if (io_error)
return NULL;
fprintf(stderr, "Out of memory error in vfat_lookup_loop\n");
return NULL;
}
return cache->entries[initpos];
}
static void accountFreeSlots(struct scan_state *ssp, struct dirCacheEntry_t *dce)
{
if(ssp->got_slots)
return;
if(ssp->free_end != dce->beginSlot)
ssp->free_start = dce->beginSlot;
ssp->free_end = dce->endSlot;
if(ssp->free_end - ssp->free_start >= ssp->size_needed)
{
ssp->got_slots = 1;
ssp->slot = ssp->free_start + ssp->size_needed - 1;
}
}
static void clear_scan(wchar_t *longname, int use_longname, struct scan_state *s)
{
s->shortmatch = s->longmatch = s->slot = -1;
s->free_end = s->got_slots = s->free_start = 0;
if (use_longname)
s->size_needed = 1 + (wcslen(longname) + VSE_NAMELEN - 1) / VSE_NAMELEN;
else
s->size_needed = 1;
}
/* lookup_for_insert replaces the old scandir function. It directly
* calls into vfat_lookup_loop, thus eliminating the overhead of the
* normal vfat_lookup
*/
int lookupForInsert(struct Stream_t *Dir,
struct direntry_t *direntry,
struct dos_name_t *dosname,
char *longname,
struct scan_state *ssp,
int ignore_entry,
int source_entry,
int pessimisticShortRename,
int use_longname)
{
wchar_t shortName[13];
wchar_t wlongname[MAX_VNAMELEN+1];
struct doscp_t *cp = GET_DOSCONVERT(Dir);
native_to_wchar(longname, wlongname, MAX_VNAMELEN+1, 0, 0);
clear_scan(wlongname, use_longname, ssp);
int ignore_match = ignore_entry == -2;
struct direntry_t entry;
initializeDirentry(&entry, Dir);
ssp->match_free = 0;
/* hash bitmap of already encountered names. Speeds up batch appends
* to huge directories, because in the best case, we only need to scan
* the new entries rather than the whole directory */
struct dirCache_t *cache = allocDirCache(Dir, 1);
if(!cache)
{
fprintf(stderr, "Out of memory error in lookupForInsert\n");
return -1; // TODO: make caller check return code?
}
if(!ignore_match)
unix_name(cp, dosname->base, dosname->ext, 0, shortName);
/* position _before_ the next answered entry */
int pos = cache->nrHashed;
if (source_entry >= 0 || (pos && isHashed(cache, wlongname)))
pos = 0;
else if(pos && !ignore_match && isHashed(cache, shortName))
{
if (pessimisticShortRename)
{
ssp->shortmatch = -2;
return 1;
}
pos = 0;
}
else if(growDirCache(cache, pos) < 0)
{
fprintf(stderr, "Out of memory error in vfat_looup [0]\n");
return -1; // TODO: make caller check return code?
}
struct dirCacheEntry_t *dce;
do
{
dce = vfat_lookup_loop_for_insert(cp, &entry, pos, cache);
switch(dce->type)
{
case DCET_FREE:
accountFreeSlots(ssp, dce);
break;
case DCET_USED:
if(!(dce->dir.attr & 0x8) && (signed int)dce->endSlot-1 == source_entry)
accountFreeSlots(ssp, dce);
/* labels never match, neither does the
* ignored entry */
if( (dce->dir.attr & 0x8) || ((signed int)dce->endSlot-1==ignore_entry))
break;
/* check long name */
if((dce->longName && !wcscasecmp(dce->longName, wlongname)) || (dce->shortName && !wcscasecmp(dce->shortName, wlongname)))
{
ssp->longmatch = dce->endSlot - 1;
/* long match is a reason for immediate stop */
direntry->beginSlot = dce->beginSlot;
direntry->endSlot = dce->endSlot-1;
return 1;
}
/* Long name or not, always check for short name match */
if (!ignore_match && !wcscasecmp(shortName, dce->shortName))
ssp->shortmatch = dce->endSlot - 1;
break;
case DCET_END:
break;
}
pos = dce->endSlot;
} while(dce->type != DCET_END);
if (ssp->shortmatch > -1)
return 1;
ssp->max_entry = dce->beginSlot;
if (ssp->got_slots)
return 6; /* Success */
/* Need more room. Can we grow the directory? */
if(!isRootDir(Dir))
return 5; /* OK, try to grow the directory */
fprintf(stderr, "No directory slots\n");
return -1;
}

View file

@ -1,104 +0,0 @@
/* Copyright 1995 David C. Niemi
* Copyright 1996-1998,2000-2003,2005,2007-2009 Alain Knaff.
* Copyright 2010 Volker Lanz (vl@fidra.de)
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MTOOLS_VFAT_H
#define MTOOLS_VFAT_H
#include <wchar.h>
struct dos_name_t;
struct direntry_t;
struct unicode_char
{
unsigned char lchar;
unsigned char uchar;
};
#define MAX_VFAT_SUBENTRIES 20 /* Max useful # of VSEs */
#define VSE_NAMELEN 13
#define VSE1SIZE 5
#define VSE2SIZE 6
#define VSE3SIZE 2
#include "stream.h"
struct vfat_subentry
{
unsigned char id; /* 0x40 = last; & 0x1f = VSE ID */
struct unicode_char text1[VSE1SIZE];
unsigned char attribute; /* 0x0f for VFAT */
unsigned char hash1; /* Always 0? */
unsigned char sum; /* Checksum of short name */
struct unicode_char text2[VSE2SIZE];
unsigned char sector_l; /* 0 for VFAT */
unsigned char sector_u; /* 0 for VFAT */
struct unicode_char text3[VSE3SIZE];
};
/* Enough size for a worst case number of full VSEs plus a null */
#define VBUFSIZE ((MAX_VFAT_SUBENTRIES*VSE_NAMELEN) + 1)
/* Max legal length of a VFAT long name */
#define MAX_VNAMELEN 255
#define VSE_PRESENT 0x01
#define VSE_LAST 0x40
#define VSE_MASK 0x1f
struct vfat_state
{
wchar_t name[VBUFSIZE];
int status; /* is now a bit map of 32 bits */
int subentries;
unsigned char sum; /* no need to remember the sum for each entry, it is the same anyways */
int present;
};
struct scan_state
{
int match_free;
int shortmatch;
int longmatch;
unsigned int free_start;
unsigned int free_end;
int slot;
int got_slots;
unsigned int size_needed;
int max_entry;
};
int unicode_write(wchar_t *, struct unicode_char *, int num, int *end);
int clear_vses(struct Stream_t *, int, size_t);
void autorename_short(struct dos_name_t *, int);
void autorename_long(char *, int);
int vfat_lookup(struct direntry_t *entry, const char *filename, int length, int flags, char *shortname, char *longname);
int dir_write(struct direntry_t *entry);
int write_vfat(struct Stream_t *, struct dos_name_t *, char *, int, struct direntry_t *);
#define DO_OPEN 1 /* open all files that are found */
#define ACCEPT_LABEL 0x08
#define ACCEPT_DIR 0x10
#define ACCEPT_PLAIN 0x20
#define MATCH_ANY 0x40
#define NO_MSG 0x80
#define NO_DOTS 0x100 /* accept no dots if matched by wildcard */
#endif

View file

@ -193,7 +193,6 @@ target_link_libraries(partitionmanagerprivate
${KDE4_SOLID_LIBS}
${UUID_LIBRARIES}
${BLKID_LIBRARIES}
libfatlabel
)
if(LIBATASMART_FOUND)

View file

@ -26,7 +26,6 @@
#include "fs/filesystem.h"
#include <qglobal.h>
#include <fatlabel/partition.h>
class CoreBackendPartition;
class Report;

View file

@ -23,8 +23,6 @@
#include "util/capacity.h"
#include "util/report.h"
#include "fatlabel/fatlabel.h"
#include <kdebug.h>
#include <klocale.h>
@ -59,7 +57,7 @@ namespace FS
m_Create = findExternal("mkfs.msdos") ? cmdSupportFileSystem : cmdSupportNone;
m_GetUsed = m_Check = findExternal("fsck.msdos", QStringList(), 2) ? cmdSupportFileSystem : cmdSupportNone;
m_GetLabel = cmdSupportCore;
m_SetLabel = cmdSupportFileSystem;
m_SetLabel = findExternal("fatlabel") ? cmdSupportFileSystem : cmdSupportNone;;
m_Move = cmdSupportCore;
m_Copy = cmdSupportCore;
m_Backup = cmdSupportCore;
@ -134,9 +132,10 @@ namespace FS
bool fat16::writeLabel(Report& report, const QString& deviceNode, const QString& newLabel)
{
report.line() << i18nc("@info/plain", "Setting label for partition <filename>%1</filename> to %2", deviceNode, newLabel);
report.line() << i18nc("@info/plain", "Setting label for partition <filename>%1</filename> to %2", deviceNode, newLabel.toUpper());
return fatlabel_set_label(deviceNode.toLocal8Bit(), newLabel.toLocal8Bit()) == 0;
ExternalCommand cmd(report, "fatlabel", QStringList() << deviceNode << newLabel.toUpper());
return cmd.run(-1) && cmd.exitCode() == 0;
}
bool fat16::check(Report& report, const QString& deviceNode) const