forked from Imagelibrary/rtems
503 lines
14 KiB
C
503 lines
14 KiB
C
/*
|
|
* MSDOS file handlers implementation
|
|
*
|
|
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
|
|
* Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.rtems.com/license/LICENSE.
|
|
*
|
|
* @(#) $Id$
|
|
*/
|
|
#if HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
|
|
#include <rtems.h>
|
|
#include <rtems/libio.h>
|
|
#include <rtems/libio_.h>
|
|
|
|
#include "fat.h"
|
|
#include "fat_fat_operations.h"
|
|
#include "fat_file.h"
|
|
|
|
#include "msdos.h"
|
|
|
|
/* msdos_file_open --
|
|
* Open fat-file which correspondes to the file
|
|
*
|
|
* PARAMETERS:
|
|
* iop - file control block
|
|
* pathname - name
|
|
* flag - flags
|
|
* mode - mode
|
|
*
|
|
* RETURNS:
|
|
* RC_OK, if file opened successfully, or -1 if error occured
|
|
* and errno set appropriately
|
|
*/
|
|
int
|
|
msdos_file_open(rtems_libio_t *iop, const char *pathname, uint32_t flag,
|
|
uint32_t mode)
|
|
{
|
|
int rc = RC_OK;
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
|
|
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
|
|
|
|
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
|
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
rtems_set_errno_and_return_minus_one(EIO);
|
|
|
|
rc = fat_file_reopen(fat_fd);
|
|
if (rc != RC_OK)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
|
|
if (iop->flags & LIBIO_FLAGS_APPEND)
|
|
iop->offset = fat_fd->fat_file_size;
|
|
|
|
iop->size = fat_fd->fat_file_size;
|
|
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return RC_OK;
|
|
}
|
|
|
|
/* msdos_file_close --
|
|
* Close fat-file which correspondes to the file. If fat-file descriptor
|
|
* which correspondes to the file is not marked "removed", synchronize
|
|
* size, first cluster number, write time and date fields of the file.
|
|
*
|
|
* PARAMETERS:
|
|
* iop - file control block
|
|
*
|
|
* RETURNS:
|
|
* RC_OK, if file closed successfully, or -1 if error occured (errno set
|
|
* appropriately)
|
|
*/
|
|
int
|
|
msdos_file_close(rtems_libio_t *iop)
|
|
{
|
|
int rc = RC_OK;
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
|
|
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
|
|
|
|
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
|
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
rtems_set_errno_and_return_minus_one(EIO);
|
|
|
|
/*
|
|
* if fat-file descriptor is not marked as "removed", synchronize
|
|
* size, first cluster number, write time and date fields of the file
|
|
*/
|
|
if (!FAT_FILE_IS_REMOVED(fat_fd))
|
|
{
|
|
rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
|
|
if (rc != RC_OK)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
|
|
rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
|
|
if (rc != RC_OK)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
|
|
rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
|
|
if (rc != RC_OK)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
rc = fat_file_close(iop->pathinfo.mt_entry, fat_fd);
|
|
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
|
|
/* msdos_file_read --
|
|
* This routine read from file pointed to by file control block into
|
|
* the specified data buffer provided by user
|
|
*
|
|
* PARAMETERS:
|
|
* iop - file control block
|
|
* buffer - buffer provided by user
|
|
* count - the number of bytes to read
|
|
*
|
|
* RETURNS:
|
|
* the number of bytes read on success, or -1 if error occured (errno set
|
|
* appropriately)
|
|
*/
|
|
ssize_t
|
|
msdos_file_read(rtems_libio_t *iop, void *buffer, size_t count)
|
|
{
|
|
ssize_t ret = 0;
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
|
|
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
|
|
|
|
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
|
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
rtems_set_errno_and_return_minus_one(EIO);
|
|
|
|
ret = fat_file_read(iop->pathinfo.mt_entry, fat_fd, iop->offset, count,
|
|
buffer);
|
|
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return ret;
|
|
}
|
|
|
|
/* msdos_file_write --
|
|
* This routine writes the specified data buffer into the file pointed to
|
|
* by file control block.
|
|
*
|
|
* PARAMETERS:
|
|
* iop - file control block
|
|
* buffer - data to write
|
|
* count - count of bytes to write
|
|
*
|
|
* RETURNS:
|
|
* the number of bytes written on success, or -1 if error occured
|
|
* and errno set appropriately
|
|
*/
|
|
ssize_t
|
|
msdos_file_write(rtems_libio_t *iop,const void *buffer, size_t count)
|
|
{
|
|
ssize_t ret = 0;
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
|
|
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
|
|
|
|
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
|
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
rtems_set_errno_and_return_minus_one(EIO);
|
|
|
|
ret = fat_file_write(iop->pathinfo.mt_entry, fat_fd, iop->offset, count,
|
|
buffer);
|
|
if (ret < 0)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* update file size in both fat-file descriptor and file control block if
|
|
* file was extended
|
|
*/
|
|
if (iop->offset + ret > fat_fd->fat_file_size)
|
|
fat_fd->fat_file_size = iop->offset + ret;
|
|
|
|
iop->size = fat_fd->fat_file_size;
|
|
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return ret;
|
|
}
|
|
|
|
/* msdos_file_lseek --
|
|
* Process lseek call to the file: extend file if lseek is up to the end
|
|
* of the file.
|
|
*
|
|
* PARAMETERS:
|
|
* iop - file control block
|
|
* offset - new offset
|
|
* whence - predefine directive
|
|
*
|
|
* RETURNS:
|
|
* new offset on success, or -1 if error occured (errno set
|
|
* appropriately).
|
|
*/
|
|
off_t
|
|
msdos_file_lseek(rtems_libio_t *iop, off_t offset, int whence)
|
|
{
|
|
int rc = RC_OK;
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
|
|
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
|
|
uint32_t real_size = 0;
|
|
|
|
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
|
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
rtems_set_errno_and_return_minus_one(EIO);
|
|
|
|
rc = fat_file_extend(iop->pathinfo.mt_entry, fat_fd, iop->offset,
|
|
&real_size);
|
|
if (rc != RC_OK)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
|
|
if (real_size > fat_fd->fat_file_size)
|
|
fat_fd->fat_file_size = iop->offset = real_size;
|
|
|
|
iop->size = fat_fd->fat_file_size;
|
|
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return iop->offset;
|
|
}
|
|
|
|
/* msdos_file_stat --
|
|
*
|
|
* PARAMETERS:
|
|
* loc - node description
|
|
* buf - stat buffer provided by user
|
|
*
|
|
* RETURNS:
|
|
* RC_OK on success, or -1 if error occured (errno set appropriately)
|
|
*/
|
|
int
|
|
msdos_file_stat(
|
|
rtems_filesystem_location_info_t *loc,
|
|
struct stat *buf
|
|
)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
|
|
fat_file_fd_t *fat_fd = loc->node_access;
|
|
|
|
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
|
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
rtems_set_errno_and_return_minus_one(EIO);
|
|
|
|
buf->st_dev = fs_info->fat.vol.dev;
|
|
buf->st_ino = fat_fd->ino;
|
|
buf->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
|
|
buf->st_rdev = 0ll;
|
|
buf->st_size = fat_fd->fat_file_size;
|
|
buf->st_blocks = fat_fd->fat_file_size >> FAT_SECTOR512_BITS;
|
|
buf->st_blksize = fs_info->fat.vol.bps;
|
|
buf->st_mtime = fat_fd->mtime;
|
|
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return RC_OK;
|
|
}
|
|
|
|
/* msdos_file_ftruncate --
|
|
* Truncate the file (if new length is greater then current do nothing).
|
|
*
|
|
* PARAMETERS:
|
|
* iop - file control block
|
|
* length - new length
|
|
*
|
|
* RETURNS:
|
|
* RC_OK on success, or -1 if error occured (errno set appropriately).
|
|
*/
|
|
int
|
|
msdos_file_ftruncate(rtems_libio_t *iop, off_t length)
|
|
{
|
|
int rc = RC_OK;
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
|
|
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
|
|
|
|
if (length >= fat_fd->fat_file_size)
|
|
return RC_OK;
|
|
|
|
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
|
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
rtems_set_errno_and_return_minus_one(EIO);
|
|
|
|
rc = fat_file_truncate(iop->pathinfo.mt_entry, fat_fd, length);
|
|
if (rc != RC_OK)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* fat_file_truncate do nothing if new length >= fat-file size, so update
|
|
* file size only if length < fat-file size
|
|
*/
|
|
if (length < fat_fd->fat_file_size)
|
|
iop->size = fat_fd->fat_file_size = length;
|
|
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return RC_OK;
|
|
}
|
|
|
|
/* msdos_file_sync --
|
|
* Synchronize file - synchronize file data and if file is not removed
|
|
* synchronize file metadata.
|
|
*
|
|
* PARAMETERS:
|
|
* iop - file control block
|
|
*
|
|
* RETURNS:
|
|
* RC_OK on success, or -1 if error occured (errno set appropriately)
|
|
*/
|
|
int
|
|
msdos_file_sync(rtems_libio_t *iop)
|
|
{
|
|
int rc = RC_OK;
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
|
|
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
|
|
|
|
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
|
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
rtems_set_errno_and_return_minus_one(EIO);
|
|
|
|
/* synchronize file data */
|
|
rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
|
|
if (rc != RC_OK)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* if fat-file descriptor is not marked "removed" - synchronize file
|
|
* metadata
|
|
*/
|
|
if (!FAT_FILE_IS_REMOVED(fat_fd))
|
|
{
|
|
rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
|
|
if (rc != RC_OK)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
|
|
if (rc != RC_OK)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
|
|
if (rc != RC_OK)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return RC_OK;
|
|
}
|
|
|
|
/* msdos_file_datasync --
|
|
* Synchronize file - synchronize only file data (metadata is letf intact).
|
|
*
|
|
* PARAMETERS:
|
|
* iop - file control block
|
|
*
|
|
* RETURNS:
|
|
* RC_OK on success, or -1 if error occured (errno set appropriately)
|
|
*/
|
|
int
|
|
msdos_file_datasync(rtems_libio_t *iop)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
|
|
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
|
|
|
|
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
|
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
rtems_set_errno_and_return_minus_one(EIO);
|
|
|
|
/* synchronize file data */
|
|
fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
|
|
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return RC_OK;
|
|
}
|
|
|
|
|
|
/* msdos_file_ioctl --
|
|
*
|
|
*
|
|
* PARAMETERS:
|
|
* iop - file control block
|
|
* ...
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
int
|
|
msdos_file_ioctl(rtems_libio_t *iop,uint32_t command, void *buffer)
|
|
{
|
|
int rc = RC_OK;
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* msdos_file_chmod --
|
|
* Change the attributes of the file. This currently does
|
|
* nothing and returns no error.
|
|
*
|
|
* PARAMETERS:
|
|
* pathloc - node description
|
|
* mode - the new mode
|
|
*
|
|
* RETURNS:
|
|
* RC_OK always
|
|
*/
|
|
int
|
|
msdos_file_chmod(rtems_filesystem_location_info_t *pathloc,
|
|
mode_t mode)
|
|
{
|
|
return RC_OK;
|
|
}
|
|
|
|
/* msdos_file_rmnod --
|
|
* Remove node associated with a file - set up first name character to
|
|
* predefined value(and write it to the disk), and mark fat-file which
|
|
* correspondes to the file as "removed"
|
|
*
|
|
* PARAMETERS:
|
|
* pathloc - node description
|
|
*
|
|
* RETURNS:
|
|
* RC_OK on success, or -1 if error occured (errno set appropriately)
|
|
*/
|
|
int
|
|
msdos_file_rmnod(rtems_filesystem_location_info_t *parent_pathloc,
|
|
rtems_filesystem_location_info_t *pathloc)
|
|
{
|
|
int rc = RC_OK;
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
|
|
fat_file_fd_t *fat_fd = pathloc->node_access;
|
|
|
|
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
|
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
rtems_set_errno_and_return_minus_one(EIO);
|
|
|
|
/* mark file removed */
|
|
rc = msdos_set_first_char4file_name(pathloc->mt_entry,
|
|
&fat_fd->dir_pos,
|
|
MSDOS_THIS_DIR_ENTRY_EMPTY);
|
|
if (rc != RC_OK)
|
|
{
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return rc;
|
|
}
|
|
|
|
fat_file_mark_removed(pathloc->mt_entry, fat_fd);
|
|
|
|
rtems_semaphore_release(fs_info->vol_sema);
|
|
return RC_OK;
|
|
}
|