source: rtems/cpukit/libfs/src/dosfs/msdos_file.c @ a7d1992c

Last change on this file since a7d1992c was 53da07e, checked in by Sebastian Huber <sebastian.huber@…>, on 05/14/12 at 13:21:30

Filesystem: PR1255: Move offset update to handlers

It is now the responsibility of the read() and write() handler to update
the offset field of the IO descriptor (rtems_libio_t). This change
makes it possible to protect the IO descriptor from concurrent access by
per file locks.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/*
2 *  MSDOS file handlers implementation
3 *
4 *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
5 *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.com/license/LICENSE.
10 */
11#if HAVE_CONFIG_H
12#include "config.h"
13#endif
14
15#include <stdlib.h>
16#include <errno.h>
17
18#include <rtems.h>
19#include <rtems/libio.h>
20#include <rtems/libio_.h>
21
22#include "fat.h"
23#include "fat_fat_operations.h"
24#include "fat_file.h"
25
26#include "msdos.h"
27
28static int
29msdos_file_update(rtems_libio_t *iop)
30{
31    int              rc = RC_OK;
32    fat_file_fd_t   *fat_fd = iop->pathinfo.node_access;
33
34    /*
35     * if fat-file descriptor is not marked as "removed", synchronize
36     * size, first cluster number, write time and date fields of the file
37     */
38    if (!FAT_FILE_IS_REMOVED(fat_fd))
39    {
40        rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
41        if (rc != RC_OK)
42        {
43            return rc;
44        }
45
46        rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
47        if (rc != RC_OK)
48        {
49            return rc;
50        }
51
52        rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
53        if (rc != RC_OK)
54        {
55            return rc;
56        }
57    }
58
59    return rc;
60}
61
62/* msdos_file_close --
63 *     Close fat-file which correspondes to the file. If fat-file descriptor
64 *     which correspondes to the file is not marked "removed", synchronize
65 *     size, first cluster number, write time and date fields of the file.
66 *
67 * PARAMETERS:
68 *     iop - file control block
69 *
70 * RETURNS:
71 *     RC_OK, if file closed successfully, or -1 if error occured (errno set
72 *     appropriately)
73 */
74int
75msdos_file_close(rtems_libio_t *iop)
76{
77    int                rc = RC_OK;
78    rtems_status_code  sc = RTEMS_SUCCESSFUL;
79    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
80
81    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
82                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
83    if (sc != RTEMS_SUCCESSFUL)
84        rtems_set_errno_and_return_minus_one(EIO);
85
86    rc = msdos_file_update(iop);
87
88    rtems_semaphore_release(fs_info->vol_sema);
89    return rc;
90}
91
92/* msdos_file_read --
93 *     This routine read from file pointed to by file control block into
94 *     the specified data buffer provided by user
95 *
96 * PARAMETERS:
97 *     iop    - file control block
98 *     buffer - buffer  provided by user
99 *     count  - the number of bytes to read
100 *
101 * RETURNS:
102 *     the number of bytes read on success, or -1 if error occured (errno set
103 *     appropriately)
104 */
105ssize_t
106msdos_file_read(rtems_libio_t *iop, void *buffer, size_t count)
107{
108    ssize_t            ret = 0;
109    rtems_status_code  sc = RTEMS_SUCCESSFUL;
110    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
111    fat_file_fd_t     *fat_fd = iop->pathinfo.node_access;
112
113    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
114                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
115    if (sc != RTEMS_SUCCESSFUL)
116        rtems_set_errno_and_return_minus_one(EIO);
117
118    ret = fat_file_read(iop->pathinfo.mt_entry, fat_fd, iop->offset, count,
119                        buffer);
120    if (ret > 0)
121        iop->offset += ret;
122
123    rtems_semaphore_release(fs_info->vol_sema);
124    return ret;
125}
126
127/* msdos_file_write --
128 *     This routine writes the specified data buffer into the file pointed to
129 *     by file control block.
130 *
131 * PARAMETERS:
132 *     iop    - file control block
133 *     buffer - data to write
134 *     count  - count of bytes to write
135 *
136 * RETURNS:
137 *     the number of bytes written on success, or -1 if error occured
138 *     and errno set appropriately
139 */
140ssize_t
141msdos_file_write(rtems_libio_t *iop,const void *buffer, size_t count)
142{
143    ssize_t            ret = 0;
144    rtems_status_code  sc = RTEMS_SUCCESSFUL;
145    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
146    fat_file_fd_t     *fat_fd = iop->pathinfo.node_access;
147
148    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
149                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
150    if (sc != RTEMS_SUCCESSFUL)
151        rtems_set_errno_and_return_minus_one(EIO);
152
153    if ((iop->flags & LIBIO_FLAGS_APPEND) != 0)
154        iop->offset = fat_fd->fat_file_size;
155
156    ret = fat_file_write(iop->pathinfo.mt_entry, fat_fd, iop->offset, count,
157                         buffer);
158    if (ret < 0)
159    {
160        rtems_semaphore_release(fs_info->vol_sema);
161        return -1;
162    }
163
164    /*
165     * update file size in both fat-file descriptor and file control block if
166     * file was extended
167     */
168    iop->offset += ret;
169    if (iop->offset > fat_fd->fat_file_size)
170        fat_fd->fat_file_size = iop->offset;
171
172    rtems_semaphore_release(fs_info->vol_sema);
173    return ret;
174}
175
176/* msdos_file_stat --
177 *
178 * PARAMETERS:
179 *     loc - node description
180 *     buf - stat buffer provided by user
181 *
182 * RETURNS:
183 *     RC_OK on success, or -1 if error occured (errno set appropriately)
184 */
185int
186msdos_file_stat(
187    const rtems_filesystem_location_info_t *loc,
188    struct stat *buf
189)
190{
191    rtems_status_code  sc = RTEMS_SUCCESSFUL;
192    msdos_fs_info_t   *fs_info = loc->mt_entry->fs_info;
193    fat_file_fd_t     *fat_fd = loc->node_access;
194
195    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
196                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
197    if (sc != RTEMS_SUCCESSFUL)
198        rtems_set_errno_and_return_minus_one(EIO);
199
200    buf->st_dev = rtems_disk_get_device_identifier(fs_info->fat.vol.dd);
201    buf->st_ino = fat_fd->ino;
202    buf->st_mode  = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
203    buf->st_rdev = 0ll;
204    buf->st_size = fat_fd->fat_file_size;
205    buf->st_blocks = fat_fd->fat_file_size >> FAT_SECTOR512_BITS;
206    buf->st_blksize = fs_info->fat.vol.bps;
207    buf->st_mtime = fat_fd->mtime;
208
209    rtems_semaphore_release(fs_info->vol_sema);
210    return RC_OK;
211}
212
213/* msdos_file_ftruncate --
214 *     Truncate the file.
215 *
216 * PARAMETERS:
217 *     iop    - file control block
218 *     length - new length
219 *
220 * RETURNS:
221 *     RC_OK on success, or -1 if error occured (errno set appropriately).
222 */
223int
224msdos_file_ftruncate(rtems_libio_t *iop, off_t length)
225{
226    int                rc = RC_OK;
227    rtems_status_code  sc = RTEMS_SUCCESSFUL;
228    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
229    fat_file_fd_t     *fat_fd = iop->pathinfo.node_access;
230    uint32_t old_length;
231
232    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
233                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
234    if (sc != RTEMS_SUCCESSFUL)
235        rtems_set_errno_and_return_minus_one(EIO);
236
237    old_length = fat_fd->fat_file_size;
238    if (length < old_length) {
239        rc = fat_file_truncate(iop->pathinfo.mt_entry, fat_fd, length);
240    } else {
241        uint32_t new_length;
242
243        rc = fat_file_extend(iop->pathinfo.mt_entry,
244                             fat_fd,
245                             true,
246                             length,
247                             &new_length);
248        if (rc == RC_OK && length != new_length) {
249            fat_file_truncate(iop->pathinfo.mt_entry, fat_fd, old_length);
250            errno = ENOSPC;
251            rc = -1;
252        }
253    }
254
255    if (rc == RC_OK) {
256        fat_fd->fat_file_size = length;
257    }
258
259    rtems_semaphore_release(fs_info->vol_sema);
260
261    return rc;
262}
263
264/* msdos_file_sync --
265 *     Synchronize file - synchronize file data and if file is not removed
266 *     synchronize file metadata.
267 *
268 * PARAMETERS:
269 *     iop - file control block
270 *
271 * RETURNS:
272 *     RC_OK on success, or -1 if error occured (errno set appropriately)
273 */
274int
275msdos_file_sync(rtems_libio_t *iop)
276{
277    int                rc = RC_OK;
278    rtems_status_code  sc = RTEMS_SUCCESSFUL;
279    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
280
281    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
282                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
283    if (sc != RTEMS_SUCCESSFUL)
284        rtems_set_errno_and_return_minus_one(EIO);
285
286    rc = msdos_file_update(iop);
287    if (rc != RC_OK)
288    {
289        rtems_semaphore_release(fs_info->vol_sema);
290        return rc;
291    }
292
293    rc = msdos_sync_unprotected(fs_info);
294
295    rtems_semaphore_release(fs_info->vol_sema);
296    return RC_OK;
297}
Note: See TracBrowser for help on using the repository browser.