| 1 | /*!
 | 
|---|
| 2 |    \file write.c
 | 
|---|
| 3 |    \ingroup (PSIO)
 | 
|---|
| 4 | */
 | 
|---|
| 5 | 
 | 
|---|
| 6 | #include <stdlib.h>
 | 
|---|
| 7 | #include <string.h>
 | 
|---|
| 8 | #include <util/psi3/libpsio/psio.h>
 | 
|---|
| 9 | 
 | 
|---|
| 10 | namespace psi3 {
 | 
|---|
| 11 | namespace libpsio {
 | 
|---|
| 12 | 
 | 
|---|
| 13 | /*!
 | 
|---|
| 14 | ** PSIO_WRITE(): Writes data to a TOC entry in a PSI file.
 | 
|---|
| 15 | **
 | 
|---|
| 16 | **  \param unit   = The PSI unit number used to identify the file to all read
 | 
|---|
| 17 | **                  and write functions.
 | 
|---|
| 18 | **  \param key    = The TOC keyword identifying the desired entry.
 | 
|---|
| 19 | **  \param buffer = The buffer from which the data is written.
 | 
|---|
| 20 | **  \param size   = The number of bytes to write.
 | 
|---|
| 21 | **  \param sadd   = The entry-relative starting page/offset to write the data.
 | 
|---|
| 22 | **  \param eadd   = A pointer to the entry-relative page/offset for the next
 | 
|---|
| 23 | **                  byte after the end of the write request.
 | 
|---|
| 24 | **
 | 
|---|
| 25 | ** \ingroup (PSIO)
 | 
|---|
| 26 | */
 | 
|---|
| 27 | 
 | 
|---|
| 28 | int psio_write(unsigned int unit, char *key, char *buffer, ULI size,
 | 
|---|
| 29 |                psio_address rel_start, psio_address *rel_end)
 | 
|---|
| 30 | {
 | 
|---|
| 31 |   psio_ud *this_unit;
 | 
|---|
| 32 |   psio_tocentry *this_entry, *last_entry;
 | 
|---|
| 33 |   psio_address address, end_address;
 | 
|---|
| 34 | 
 | 
|---|
| 35 |   this_unit = &(psio_unit[unit]);
 | 
|---|
| 36 | 
 | 
|---|
| 37 |   /* Find the entry in the TOC */
 | 
|---|
| 38 |   this_entry = psio_tocscan(unit, key);
 | 
|---|
| 39 | 
 | 
|---|
| 40 |   if(this_entry == NULL) { /* New TOC entry */
 | 
|---|
| 41 |     if(rel_start.page||rel_start.offset) psio_error(unit,PSIO_ERROR_BLKSTART);
 | 
|---|
| 42 | 
 | 
|---|
| 43 |     this_entry = (psio_tocentry *) malloc(sizeof(psio_tocentry));
 | 
|---|
| 44 |     strcpy(this_entry->key,key);
 | 
|---|
| 45 |     this_entry->next = NULL;
 | 
|---|
| 46 |     this_entry->last = NULL;
 | 
|---|
| 47 | 
 | 
|---|
| 48 |     /* Compute the address of the entry */
 | 
|---|
| 49 |     if(!(this_unit->toclen)) { /* First TOC entry */
 | 
|---|
| 50 |       this_entry->sadd.page = 0;
 | 
|---|
| 51 |       this_entry->sadd.offset = 3*sizeof(ULI);
 | 
|---|
| 52 | 
 | 
|---|
| 53 |       this_unit->toc = this_entry;
 | 
|---|
| 54 |     }
 | 
|---|
| 55 |     else {  /* Use ending address from last TOC entry */
 | 
|---|
| 56 |       last_entry = psio_toclast(unit);
 | 
|---|
| 57 |       this_entry->sadd = last_entry->eadd;
 | 
|---|
| 58 | 
 | 
|---|
| 59 |       last_entry->next = this_entry;
 | 
|---|
| 60 |       this_entry->last = last_entry;
 | 
|---|
| 61 |     }
 | 
|---|
| 62 | 
 | 
|---|
| 63 |     /* Data for the write call */
 | 
|---|
| 64 |     address = this_entry->sadd;
 | 
|---|
| 65 | 
 | 
|---|
| 66 |     /* Set the end address for this_entry */
 | 
|---|
| 67 |     this_entry->eadd = psio_get_address(this_entry->sadd, size);
 | 
|---|
| 68 | 
 | 
|---|
| 69 |     /* Update the unit's TOC stats */
 | 
|---|
| 70 |     this_unit->toclen++;
 | 
|---|
| 71 |     this_unit->tocaddress = this_entry->eadd;
 | 
|---|
| 72 | 
 | 
|---|
| 73 |     /* Update the rel_end argument value for the caller */
 | 
|---|
| 74 |     *rel_end = psio_get_address(rel_start,size);
 | 
|---|
| 75 |   }
 | 
|---|
| 76 |   else { /* Old TOC entry */
 | 
|---|
| 77 | 
 | 
|---|
| 78 |     /* Compute the global starting page and offset for the block */
 | 
|---|
| 79 |     address = psio_get_global_address(this_entry->sadd, rel_start);
 | 
|---|
| 80 | 
 | 
|---|
| 81 |     /* Make sure this block doesn't start past the end of the entry */
 | 
|---|
| 82 |     if(address.page > this_entry->eadd.page)
 | 
|---|
| 83 |       psio_error(unit,PSIO_ERROR_BLKSTART);
 | 
|---|
| 84 |     else if((address.page == this_entry->eadd.page) &&
 | 
|---|
| 85 |             (address.offset > this_entry->eadd.offset))
 | 
|---|
| 86 |       psio_error(unit,PSIO_ERROR_BLKSTART);
 | 
|---|
| 87 | 
 | 
|---|
| 88 |     /* Compute the new global ending address for the entry, if necessary */
 | 
|---|
| 89 |     end_address = psio_get_address(address, size);
 | 
|---|
| 90 |     if(end_address.page > this_entry->eadd.page) {
 | 
|---|
| 91 |       if(this_entry->next != NULL) {
 | 
|---|
| 92 |         fprintf(stderr, "PSIO_ERROR: Attempt to write into next entry: %d, %s\n", 
 | 
|---|
| 93 |                 unit, key);
 | 
|---|
| 94 |         psio_error(unit, PSIO_ERROR_BLKEND);
 | 
|---|
| 95 |       }
 | 
|---|
| 96 |       this_entry->eadd = end_address;
 | 
|---|
| 97 |       this_unit->tocaddress = end_address;
 | 
|---|
| 98 |           
 | 
|---|
| 99 |     }
 | 
|---|
| 100 |     else if((end_address.page == this_entry->eadd.page) &&
 | 
|---|
| 101 |             (end_address.offset > this_entry->eadd.offset))
 | 
|---|
| 102 |       {
 | 
|---|
| 103 |         if(this_entry->next != NULL) {
 | 
|---|
| 104 |           fprintf(stderr, "PSIO_ERROR: Attempt to write into next entry: %d, %s\n", 
 | 
|---|
| 105 |                   unit, key);
 | 
|---|
| 106 |           psio_error(unit, PSIO_ERROR_BLKEND);
 | 
|---|
| 107 |         }
 | 
|---|
| 108 |         this_entry->eadd = end_address;
 | 
|---|
| 109 |         this_unit->tocaddress = end_address;
 | 
|---|
| 110 |       }
 | 
|---|
| 111 | 
 | 
|---|
| 112 |     /* Update the eadd argument value for the caller */
 | 
|---|
| 113 |     *rel_end = psio_get_address(rel_start, size);
 | 
|---|
| 114 |   }
 | 
|---|
| 115 | 
 | 
|---|
| 116 |   /* Now write the actual data to the unit */
 | 
|---|
| 117 |   psio_rw(unit, buffer, address, size, 1);
 | 
|---|
| 118 | 
 | 
|---|
| 119 | #ifdef PSIO_STATS
 | 
|---|
| 120 |   psio_writlen[unit] += size;
 | 
|---|
| 121 | #endif
 | 
|---|
| 122 | 
 | 
|---|
| 123 |   return(0);
 | 
|---|
| 124 | }
 | 
|---|
| 125 | 
 | 
|---|
| 126 | }
 | 
|---|
| 127 | }
 | 
|---|