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 | }
|
---|