Use mtools to set FAT labels.

Partition Manager used its internal fork of mtools to avoid setting up
device to drive letter mappings. It looks like recent versions of
mtools can be used without it by using special device ::
This commit is contained in:
Andrius Štikonas 2015-04-29 00:39:36 +01:00
parent e63b0e43e9
commit 47bf8bb72d
46 changed files with 4 additions and 6552 deletions

View File

@ -78,7 +78,6 @@ pkg_check_modules(LIBATASMART REQUIRED libatasmart)
include_directories(${Qt5Core_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} ${BLKID_INCLUDE_DIRS} lib/ src/)
add_subdirectory(lib)
add_subdirectory(src)
add_subdirectory(icons)
add_subdirectory(doc)

View File

@ -1,17 +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 3 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, see <http://www.gnu.org/licenses/>.
add_subdirectory(fatlabel)

View File

@ -1,11 +0,0 @@
[Buildset]
BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x0c\x00m\x00l\x00a\x00b\x00e\x00l)
[CMake]
BuildDirs[$e]=$HOME/dev/mlabel/trunk/build
CMakeDir=/usr/share/cmake-2.6/Modules
Current CMake Binary=file:///usr/bin/cmake
CurrentBuildDir=file:///home/vl/dev/mlabel/trunk/build
CurrentBuildType=
CurrentInstallDir=file:///usr/local
ProjectRootRelative=./

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 3 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, see <http://www.gnu.org/licenses/>.
set(CMAKE_VISIBILITY_INLINES_HIDDEN 0)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -std=gnu11 -Wno-sign-compare -Wno-type-limits -fno-strict-aliasing")
file(GLOB libfatlabel_SRCS
*.c
)
include_directories(.)
add_definitions(-D_LARGEFILE64_SOURCE -D_GNU_SOURCE)
############################################
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,55 +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 3 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, see <http://www.gnu.org/licenses/>.*
*************************************************************************/
#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,31 +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 3 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, see <http://www.gnu.org/licenses/>.*
*************************************************************************/
#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,425 +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>
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

@ -51,7 +51,7 @@ install(FILES partitionmanager.kcfg DESTINATION ${KCFG_INSTALL_DIR})
add_library(kpmcore SHARED ${kpmcore_SRCS})
generate_export_header(kpmcore EXPORT_FILE_NAME libpartitionmanager_export.h)
target_link_libraries( kpmcore libfatlabel
target_link_libraries( kpmcore
${UUID_LIBRARIES} ${BLKID_LIBRARIES} ${LIBATASMART_LIBRARIES}
KF5::ConfigCore
KF5::ConfigGui

View File

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

View File

@ -21,8 +21,6 @@
#include "util/capacity.h"
#include "util/report.h"
#include "fatlabel/fatlabel.h"
#include <KLocalizedString>
#include <QString>
@ -56,7 +54,7 @@ namespace FS
m_Create = findExternal(QStringLiteral("mkfs.msdos")) ? cmdSupportFileSystem : cmdSupportNone;
m_GetUsed = m_Check = findExternal(QStringLiteral("fsck.msdos"), QStringList(), 2) ? cmdSupportFileSystem : cmdSupportNone;
m_GetLabel = cmdSupportCore;
m_SetLabel = cmdSupportFileSystem;
m_SetLabel = findExternal(QStringLiteral("mlabel")) ? cmdSupportFileSystem : cmdSupportNone;
m_Move = cmdSupportCore;
m_Copy = cmdSupportCore;
m_Backup = cmdSupportCore;
@ -133,7 +131,8 @@ namespace FS
{
report.line() << xi18nc("@info/plain", "Setting label for partition <filename>%1</filename> to %2", deviceNode, newLabel);
return fatlabel_set_label(deviceNode.toLocal8Bit().constData(), newLabel.toLocal8Bit().constData()) == 0;
ExternalCommand cmd(report, QStringLiteral("mlabel"), QStringList() << QStringLiteral("-i") << deviceNode << QStringLiteral("::") + newLabel);
return cmd.run(-1) && cmd.exitCode() == 0;
}
bool fat16::check(Report& report, const QString& deviceNode) const