summaryrefslogblamecommitdiffstats
path: root/cpukit/libfs/src/dosfs/msdos_file.c
blob: ada943d854f8ae19ef9f219a66ac63c14928cbd9 (plain) (tree)
1
2
3
4
5
6
7
8

        
  




                                            




                                                           
                                         





                   











                               









                                                                        
                                                                             

                     
       
                                                               
 
                               
                                             
                                                                 
                                                          



                                                                
                                                  
 
                                                                  
                                

                           





                                               
                                                                             










                                                                     
       
                                                                     
 
                               
                                             
                                                                 
                                                          



                                                                
                                                  
 


                                               
                                                                   


                                 
                                                   


                  

                                                                             

                        

                                            
                                                               
 


                                                     



                                               








                                                                         
   
                

                                                
 

                                             
                                                        
                                                 
                                                          



                                                                
                                                  
 
                                                                        
                              
                                                          

                                         


                                                                   

                                  






                                               
                         


                                  
                          



                                                                          
   
                                                      


                                             
                                                                 
                                                          
                        



                                                                
                                                  
 

                                       
                                                              


                            
                                           




                                                  
                                                                 


                           

     

                    
                                               
                                                     
     
 
                                               

              


                     
                                                                          












                                                                         
                                                                 
                                                          
 


                                                                
                                                  
 
                                                





                                                   
                                 
 
                                               

                                                
 
                 
 
/**
 * @file
 *
 * @brief MSDOS File Handlers Implementation
 * @ingroup libfs
 */

/*
 *  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.org/license/LICENSE.
 */
#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_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(&fs_info->fat, fat_fd, iop->offset, count,
                        buffer);
    if (ret > 0)
        iop->offset += ret;

    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);

    if ((iop->flags & LIBIO_FLAGS_APPEND) != 0)
        iop->offset = fat_fd->fat_file_size;

    ret = fat_file_write(&fs_info->fat, 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
     */
    iop->offset += ret;
    if (iop->offset > fat_fd->fat_file_size)
        fat_file_set_file_size(fat_fd, (uint32_t) iop->offset);

    if (ret > 0)
        fat_file_set_ctime_mtime(fat_fd, time(NULL));

    rtems_semaphore_release(fs_info->vol_sema);
    return ret;
}

/* 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(
    const 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;
    uint32_t           cl_mask = fs_info->fat.vol.bpc - 1;

    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 = rtems_disk_get_device_identifier(fs_info->fat.vol.dd);
    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 + cl_mask) & ~cl_mask)
      >> FAT_SECTOR512_BITS;
    buf->st_blksize = fs_info->fat.vol.bpc;
    buf->st_atime = fat_fd->mtime;
    buf->st_ctime = fat_fd->ctime;
    buf->st_mtime = fat_fd->mtime;

    rtems_semaphore_release(fs_info->vol_sema);
    return RC_OK;
}

/* msdos_file_ftruncate --
 *     Truncate the file.
 *
 * 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;
    uint32_t old_length;

    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);

    old_length = fat_fd->fat_file_size;
    if (length < old_length) {
        rc = fat_file_truncate(&fs_info->fat, fat_fd, length);
    } else {
        uint32_t new_length;

        rc = fat_file_extend(&fs_info->fat,
                             fat_fd,
                             true,
                             length,
                             &new_length);
        if (rc == RC_OK && length != new_length) {
            fat_file_truncate(&fs_info->fat, fat_fd, old_length);
            errno = ENOSPC;
            rc = -1;
        }
    }

    if (rc == RC_OK)
    {
        fat_file_set_file_size(fat_fd, length);
        fat_file_set_ctime_mtime(fat_fd, time(NULL));
    }

    rtems_semaphore_release(fs_info->vol_sema);

    return rc;
}

/* 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;
    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_update(&fs_info->fat, fat_fd);
    if (rc != RC_OK)
    {
        rtems_semaphore_release(fs_info->vol_sema);
        return rc;
    }

    rc = fat_sync(&fs_info->fat);

    rtems_semaphore_release(fs_info->vol_sema);
    if ( rc != 0 )
      rtems_set_errno_and_return_minus_one(EIO);

    return RC_OK;
}