source: rtems/cpukit/libfs/src/rfs/rtems-rfs-file.c @ 0ec9bbc

5
Last change on this file since 0ec9bbc was d8ec270b, checked in by Sebastian Huber <sebastian.huber@…>, on 04/07/16 at 08:29:09

libblock: Drop superfluous <stdlib.h> include

Drop superfluous <stdlib.h> include from <rtems/diskdevs.h> since this
leads to conflicts with the latest Newlib in case this header file is
used in the FreeBSD kernel space, e.g. for USB mass storage support.

  • Property mode set to 100644
File size: 18.5 KB
Line 
1/**
2 * @file
3 *
4 * @brief RTEMS File Systems File Routines
5 * @ingroup rtems_rfs
6 *
7 * These functions manage files.
8 */
9
10/*
11 *  COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.org/license/LICENSE.
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <inttypes.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <rtems/rfs/rtems-rfs-block-pos.h>
27#include <rtems/rfs/rtems-rfs-file.h>
28#include <rtems/rfs/rtems-rfs-file-system.h>
29#include <rtems/rfs/rtems-rfs-trace.h>
30
31int
32rtems_rfs_file_open (rtems_rfs_file_system*  fs,
33                     rtems_rfs_ino           ino,
34                     int                     oflag,
35                     rtems_rfs_file_handle** file)
36{
37  rtems_rfs_file_handle* handle;
38  rtems_rfs_file_shared* shared;
39  int                    rc;
40
41  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
42    printf ("rtems-rfs: file-open: ino=%" PRId32 "\n", ino);
43
44  *file = NULL;
45
46  /*
47   * Allocate a new handle and initialise it. Do this before we deal with the
48   * shared node data so we do not have to be concerned with reference
49   * counting.
50   */
51  handle = malloc (sizeof (rtems_rfs_file_handle));
52  if (!handle)
53    return ENOMEM;
54
55  memset (handle, 0, sizeof (rtems_rfs_file_handle));
56
57  rc = rtems_rfs_buffer_handle_open (fs, &handle->buffer);
58  if (rc > 0)
59  {
60    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
61      printf ("rtems-rfs: file-open: buffer handle open failed: %d: %s\n",
62              rc, strerror (rc));
63    free (handle);
64    return rc;
65  }
66
67  /*
68   * Scan the file system data list of open files for this ino. If found up
69   * the reference count and return the pointer to the data.
70   */
71  shared = rtems_rfs_file_get_shared (fs, ino);
72  if (shared)
73  {
74    shared->references++;
75    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
76      printf ("rtems-rfs: file-open: ino=%" PRId32 " shared\n", ino);
77  }
78  else
79  {
80    /*
81     * None exists so create. Copy in the shared parts of the inode we hold in
82     * memory.
83     */
84    shared = malloc (sizeof (rtems_rfs_file_shared));
85    if (!shared)
86    {
87      rtems_rfs_buffer_handle_close (fs, &handle->buffer);
88      free (handle);
89      return ENOMEM;
90    }
91
92    memset (shared, 0, sizeof (rtems_rfs_file_shared));
93
94    rc = rtems_rfs_inode_open (fs, ino, &shared->inode, true);
95    if (rc > 0)
96    {
97      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
98        printf ("rtems-rfs: file-open: inode open failed: %d: %s\n",
99                rc, strerror (rc));
100      free (shared);
101      rtems_rfs_buffer_handle_close (fs, &handle->buffer);
102      free (handle);
103      return rc;
104    }
105
106    rc = rtems_rfs_block_map_open (fs, &shared->inode, &shared->map);
107    if (rc > 0)
108    {
109      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
110        printf ("rtems-rfs: file-open: block map open failed: %d: %s\n",
111                rc, strerror (rc));
112      rtems_rfs_inode_close (fs, &shared->inode);
113      free (shared);
114      rtems_rfs_buffer_handle_close (fs, &handle->buffer);
115      free (handle);
116      return rc;
117    }
118
119    shared->references = 1;
120    shared->size.count = rtems_rfs_inode_get_block_count (&shared->inode);
121    shared->size.offset = rtems_rfs_inode_get_block_offset (&shared->inode);
122    shared->atime = rtems_rfs_inode_get_atime (&shared->inode);
123    shared->mtime = rtems_rfs_inode_get_mtime (&shared->inode);
124    shared->ctime = rtems_rfs_inode_get_ctime (&shared->inode);
125    shared->fs = fs;
126
127    rtems_chain_append_unprotected (&fs->file_shares, &shared->link);
128
129    rtems_rfs_inode_unload (fs, &shared->inode, false);
130
131    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
132      printf ("rtems-rfs: file-open: ino=%" PRId32 " share created\n", ino);
133  }
134
135  handle->flags  = oflag;
136  handle->shared = shared;
137
138  *file = handle;
139
140  return 0;
141}
142
143int
144rtems_rfs_file_close (rtems_rfs_file_system* fs,
145                      rtems_rfs_file_handle* handle)
146{
147  int rrc;
148  int rc;
149
150  rrc = 0;
151
152  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
153    printf ("rtems-rfs: file-close: entry: ino=%" PRId32 "\n",
154            handle->shared->inode.ino);
155
156  if (handle->shared->references > 0)
157    handle->shared->references--;
158
159  if (handle->shared->references == 0)
160  {
161    if (!rtems_rfs_inode_is_loaded (&handle->shared->inode))
162      rrc = rtems_rfs_inode_load (fs, &handle->shared->inode);
163
164    if (rrc == 0)
165    {
166      /*
167       * @todo This could be clever and only update if different.
168       */
169      rtems_rfs_inode_set_atime (&handle->shared->inode,
170                                 handle->shared->atime);
171      rtems_rfs_inode_set_mtime (&handle->shared->inode,
172                                 handle->shared->mtime);
173      rtems_rfs_inode_set_ctime (&handle->shared->inode,
174                                 handle->shared->ctime);
175      if (!rtems_rfs_block_size_equal (&handle->shared->size,
176                                       &handle->shared->map.size))
177        rtems_rfs_block_map_set_size (&handle->shared->map,
178                                      &handle->shared->size);
179    }
180
181    rc = rtems_rfs_block_map_close (fs, &handle->shared->map);
182    if (rc > 0)
183    {
184      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
185        printf ("rtems-rfs: file-close: map close error: ino=%" PRId32 ": %d: %s\n",
186                handle->shared->inode.ino, rc, strerror (rc));
187      if (rrc == 0)
188        rrc = rc;
189    }
190
191    rc = rtems_rfs_inode_close (fs, &handle->shared->inode);
192    if (rc > 0)
193    {
194      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
195        printf ("rtems-rfs: file-close: inode close error: ino=%" PRId32 ": %d: %s\n",
196                handle->shared->inode.ino, rc, strerror (rc));
197      if (rrc == 0)
198        rrc = rc;
199    }
200
201    rtems_chain_extract_unprotected (&handle->shared->link);
202    free (handle->shared);
203  }
204
205  rc = rtems_rfs_buffer_handle_close (fs, &handle->buffer);
206  if ((rrc == 0) && (rc > 0))
207    rrc = rc;
208
209  if (rrc > 0)
210  {
211    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
212      printf ("rtems-rfs: file-close: result: %d: %s\n", rrc, strerror (rrc));
213  }
214
215  free (handle);
216
217  return rrc;
218}
219
220int
221rtems_rfs_file_io_start (rtems_rfs_file_handle* handle,
222                         size_t*                available,
223                         bool                   read)
224{
225  size_t size;
226
227  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
228    printf ("rtems-rfs: file-io: start: %s pos=%" PRIu32 ":%" PRIu32 "\n",
229            read ? "read" : "write",  handle->bpos.bno, handle->bpos.boff);
230
231  if (!rtems_rfs_buffer_handle_has_block (&handle->buffer))
232  {
233    rtems_rfs_buffer_block block;
234    bool                   request_read;
235    int                    rc;
236
237    request_read = read;
238
239    rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
240                                   rtems_rfs_file_map (handle),
241                                   rtems_rfs_file_bpos (handle),
242                                   &block);
243    if (rc > 0)
244    {
245      /*
246       * Has the read reached the EOF ?
247       */
248      if (read && (rc == ENXIO))
249      {
250        *available = 0;
251        return 0;
252      }
253
254      if (rc != ENXIO)
255        return rc;
256
257      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
258        printf ("rtems-rfs: file-io: start: grow\n");
259
260      rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
261                                     rtems_rfs_file_map (handle),
262                                     1, &block);
263      if (rc > 0)
264        return rc;
265
266      request_read = false;
267    }
268    else
269    {
270      /*
271       * If this is a write check if the write starts within a block or the
272       * amount of data is less than a block size. If it is read the block
273       * rather than getting a block to fill.
274       */
275      if (!read &&
276          (rtems_rfs_file_block_offset (handle) ||
277           (*available < rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))))
278        request_read = true;
279    }
280
281    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
282      printf ("rtems-rfs: file-io: start: block=%" PRIu32 " request-read=%s\n",
283              block, request_read ? "yes" : "no");
284
285    rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
286                                          rtems_rfs_file_buffer (handle),
287                                          block, request_read);
288    if (rc > 0)
289      return rc;
290  }
291
292  if (read
293      && rtems_rfs_block_map_last (rtems_rfs_file_map (handle))
294      && rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle)))
295    size = rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
296  else
297    size = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
298
299  *available = size - rtems_rfs_file_block_offset (handle);
300
301  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
302    printf ("rtems-rfs: file-io: start: available=%zu (%zu)\n",
303            *available, size);
304
305  return 0;
306}
307
308int
309rtems_rfs_file_io_end (rtems_rfs_file_handle* handle,
310                       size_t                 size,
311                       bool                   read)
312{
313  bool atime;
314  bool mtime;
315  bool length;
316  int  rc = 0;
317
318  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
319    printf ("rtems-rfs: file-io:   end: %s size=%zu\n",
320            read ? "read" : "write", size);
321
322  if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
323  {
324    if (!read)
325      rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
326    rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
327                                          rtems_rfs_file_buffer (handle));
328    if (rc > 0)
329    {
330      printf (
331        "rtems-rfs: file-io:   end: error on release: %s size=%zu: %d: %s\n",
332        read ? "read" : "write", size, rc, strerror (rc));
333
334      return rc;
335    }
336  }
337
338  /*
339   * Update the handle's position. Only a block size can be handled at a time
340   * so no special maths is needed. If the offset is bigger than the block size
341   * increase the block number and adjust the offset.
342   *
343   * If we are the last block and the position is past the current size update
344   * the size with the new length. The map holds the block count.
345   */
346  handle->bpos.boff += size;
347
348  if (handle->bpos.boff >=
349      rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))
350  {
351    handle->bpos.bno++;
352    handle->bpos.boff -= rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
353  }
354
355  length = false;
356  mtime = !read;
357
358  if (!read &&
359      rtems_rfs_block_map_past_end (rtems_rfs_file_map (handle),
360                                    rtems_rfs_file_bpos (handle)))
361  {
362    rtems_rfs_block_map_set_size_offset (rtems_rfs_file_map (handle),
363                                         handle->bpos.boff);
364    length = true;
365  }
366
367  atime  = rtems_rfs_file_update_atime (handle);
368  mtime  = rtems_rfs_file_update_mtime (handle) && mtime;
369  length = rtems_rfs_file_update_length (handle) && length;
370
371  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
372    printf ("rtems-rfs: file-io:   end: pos=%" PRIu32 ":%" PRIu32 " %c %c %c\n",
373            handle->bpos.bno, handle->bpos.boff,
374            atime ? 'A' : '-', mtime ? 'M' : '-', length ? 'L' : '-');
375
376  if (atime || mtime)
377  {
378    time_t now = time (NULL);
379    if (read && atime)
380      handle->shared->atime = now;
381    if (!read && mtime)
382      handle->shared->mtime = now;
383  }
384  if (length)
385  {
386    handle->shared->size.count =
387      rtems_rfs_block_map_count (rtems_rfs_file_map (handle));
388    handle->shared->size.offset =
389      rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
390  }
391
392  return rc;
393}
394
395int
396rtems_rfs_file_io_release (rtems_rfs_file_handle* handle)
397{
398  int rc = 0;
399  if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
400    rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
401                                          rtems_rfs_file_buffer (handle));
402  return rc;
403}
404
405int
406rtems_rfs_file_seek (rtems_rfs_file_handle* handle,
407                     rtems_rfs_pos          pos,
408                     rtems_rfs_pos*         new_pos)
409{
410  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
411    printf ("rtems-rfs: file-seek: new=%" PRIu64 "\n", pos);
412
413  /*
414   * This call only sets the position if it is in a valid part of the file. The
415   * user can request past the end of the file then write to extend the
416   * file. The lseek entry states:
417   *
418   *    "Although lseek() may position the file offset beyond the end of the
419   *     file, this function does not itself extend the size of the file."
420   *
421   * This means the file needs to set the file size to the pos only when a
422   * write occurs.
423   */
424  if (pos <= rtems_rfs_file_shared_get_size (rtems_rfs_file_fs (handle),
425                                            handle->shared))
426  {
427    rtems_rfs_file_set_bpos (handle, pos);
428
429    /*
430     * If the file has a block check if it maps to the current position and it
431     * does not release it. That will force us to get the block at the new
432     * position when the I/O starts.
433     */
434    if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
435    {
436      rtems_rfs_buffer_block block;
437      int                    rc;
438
439      rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
440                                     rtems_rfs_file_map (handle),
441                                     rtems_rfs_file_bpos (handle),
442                                     &block);
443      if (rc > 0)
444        return rc;
445      if (rtems_rfs_buffer_bnum (&handle->buffer) != block)
446      {
447        rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
448                                              rtems_rfs_file_buffer (handle));
449        if (rc > 0)
450          return rc;
451      }
452    }
453  }
454  else
455  {
456    /*
457     * The seek is outside the current file so release any buffer. A write will
458     * extend the file.
459     */
460    int rc = rtems_rfs_file_io_release (handle);
461    if (rc > 0)
462      return rc;
463  }
464
465  *new_pos = pos;
466  return 0;
467}
468
469int
470rtems_rfs_file_set_size (rtems_rfs_file_handle* handle,
471                         rtems_rfs_pos          new_size)
472{
473  rtems_rfs_block_map* map  = rtems_rfs_file_map (handle);
474  rtems_rfs_pos        size;
475  int                  rc;
476
477  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
478    printf ("rtems-rfs: file-set-size: size=%" PRIu64 "\n", new_size);
479
480  size = rtems_rfs_file_size (handle);
481
482  /*
483   * If the file is same size do nothing else grow or shrink it ?
484   *
485   * If the file does not change size do not update the times.
486   */
487  if (size != new_size)
488  {
489    /*
490     * Short cut for the common truncate on open call.
491     */
492    if (new_size == 0)
493    {
494      rc = rtems_rfs_block_map_free_all (rtems_rfs_file_fs (handle), map);
495      if (rc > 0)
496        return rc;
497    }
498    else
499    {
500      if (size < new_size)
501      {
502        /*
503         * Grow. Fill with 0's.
504         */
505        rtems_rfs_pos count;
506        uint32_t      length;
507        bool          read_block;
508
509        count = new_size - size;
510        length = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
511        read_block = false;
512
513        while (count)
514        {
515          rtems_rfs_buffer_block block;
516          rtems_rfs_block_pos    bpos;
517          uint8_t*               dst;
518
519          /*
520           * Get the block position for the current end of the file as seen by
521           * the map. If not found and the EOF grow the map then fill the block
522           * with 0.
523           */
524          rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map), &bpos);
525          rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
526                                         map, &bpos, &block);
527          if (rc > 0)
528          {
529            /*
530             * Have we reached the EOF ?
531             */
532            if (rc != ENXIO)
533              return rc;
534
535            rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
536                                           map, 1, &block);
537            if (rc > 0)
538              return rc;
539          }
540
541          if (count < (length - bpos.boff))
542          {
543            length = count + bpos.boff;
544            read_block = true;
545            rtems_rfs_block_map_set_size_offset (map, length);
546          }
547          else
548          {
549            rtems_rfs_block_map_set_size_offset (map, 0);
550          }
551
552          /*
553           * Only read the block if the length is not the block size.
554           */
555          rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
556                                                rtems_rfs_file_buffer (handle),
557                                                block, read_block);
558          if (rc > 0)
559            return rc;
560
561          dst = rtems_rfs_buffer_data (&handle->buffer);
562          memset (dst + bpos.boff, 0, length - bpos.boff);
563
564          rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
565
566          rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
567                                                rtems_rfs_file_buffer (handle));
568          if (rc > 0)
569            return rc;
570
571          count -= length - bpos.boff;
572        }
573      }
574      else
575      {
576        /*
577         * Shrink
578         */
579        rtems_rfs_block_no blocks;
580        uint32_t           offset;
581
582        blocks =
583          rtems_rfs_block_map_count (map) -
584          (((new_size - 1) /
585            rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle))) + 1);
586
587        offset =
588          new_size % rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
589
590        if (blocks)
591        {
592          int rc;
593          rc = rtems_rfs_block_map_shrink (rtems_rfs_file_fs (handle),
594                                           rtems_rfs_file_map (handle),
595                                           blocks);
596          if (rc > 0)
597            return rc;
598        }
599
600        rtems_rfs_block_map_set_size_offset (map, offset);
601
602        if (rtems_rfs_block_pos_past_end (rtems_rfs_file_bpos (handle),
603                                          rtems_rfs_block_map_size (map)))
604          rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map),
605                                         rtems_rfs_file_bpos (handle));
606      }
607    }
608
609    handle->shared->size.count  = rtems_rfs_block_map_count (map);
610    handle->shared->size.offset = rtems_rfs_block_map_size_offset (map);
611  }
612
613  if (rtems_rfs_file_update_mtime (handle))
614    handle->shared->mtime = time (NULL);
615
616  return 0;
617}
618
619rtems_rfs_file_shared*
620rtems_rfs_file_get_shared (rtems_rfs_file_system* fs,
621                           rtems_rfs_ino          ino)
622{
623  rtems_chain_node* node;
624  node = rtems_chain_first (&fs->file_shares);
625  while (!rtems_chain_is_tail (&fs->file_shares, node))
626  {
627    rtems_rfs_file_shared* shared;
628    shared = (rtems_rfs_file_shared*) node;
629    if (shared->inode.ino == ino)
630      return shared;
631    node = rtems_chain_next (node);
632  }
633  return NULL;
634}
Note: See TracBrowser for help on using the repository browser.