11
** PSIO_WRITE(): Writes data to a TOC entry in a PSI file.
13
** \param unit = The PSI unit number used to identify the file to all read
14
** and write functions.
15
** \param key = The TOC keyword identifying the desired entry.
16
** \param buffer = The buffer from which the data is written.
17
** \param size = The number of bytes to write.
18
** \param sadd = The entry-relative starting page/offset to write the data.
19
** \param eadd = A pointer to the entry-relative page/offset for the next
20
** byte after the end of the write request.
25
int psio_write(unsigned int unit, char *key, char *buffer, ULI size,
26
psio_address rel_start, psio_address *rel_end)
29
psio_tocentry *this_entry, *last_entry;
30
psio_address address, end_address;
32
this_unit = &(psio_unit[unit]);
34
/* Find the entry in the TOC */
35
this_entry = psio_tocscan(unit, key);
37
if(this_entry == NULL) { /* New TOC entry */
38
if(rel_start.page||rel_start.offset) psio_error(unit,PSIO_ERROR_BLKSTART);
40
this_entry = (psio_tocentry *) malloc(sizeof(psio_tocentry));
41
strcpy(this_entry->key,key);
42
this_entry->next = NULL;
43
this_entry->last = NULL;
45
/* Compute the address of the entry */
46
if(!(this_unit->toclen)) { /* First TOC entry */
47
this_entry->sadd.page = 0;
48
this_entry->sadd.offset = 3*sizeof(ULI);
50
this_unit->toc = this_entry;
52
else { /* Use ending address from last TOC entry */
53
last_entry = psio_toclast(unit);
54
this_entry->sadd = last_entry->eadd;
56
last_entry->next = this_entry;
57
this_entry->last = last_entry;
60
/* Data for the write call */
61
address = this_entry->sadd;
63
/* Set the end address for this_entry */
64
this_entry->eadd = psio_get_address(this_entry->sadd, size);
66
/* Update the unit's TOC stats */
68
this_unit->tocaddress = this_entry->eadd;
70
/* Update the rel_end argument value for the caller */
71
*rel_end = psio_get_address(rel_start,size);
73
else { /* Old TOC entry */
75
/* Compute the global starting page and offset for the block */
76
address = psio_get_global_address(this_entry->sadd, rel_start);
78
/* Make sure this block doesn't start past the end of the entry */
79
if(address.page > this_entry->eadd.page)
80
psio_error(unit,PSIO_ERROR_BLKSTART);
81
else if((address.page == this_entry->eadd.page) &&
82
(address.offset > this_entry->eadd.offset))
83
psio_error(unit,PSIO_ERROR_BLKSTART);
85
/* Compute the new global ending address for the entry, if necessary */
86
end_address = psio_get_address(address, size);
87
if(end_address.page > this_entry->eadd.page) {
88
if(this_entry->next != NULL) {
89
fprintf(stderr, "PSIO_ERROR: Attempt to write into next entry: %d, %s\n",
91
psio_error(unit, PSIO_ERROR_BLKEND);
93
this_entry->eadd = end_address;
94
this_unit->tocaddress = end_address;
97
else if((end_address.page == this_entry->eadd.page) &&
98
(end_address.offset > this_entry->eadd.offset))
100
if(this_entry->next != NULL) {
101
fprintf(stderr, "PSIO_ERROR: Attempt to write into next entry: %d, %s\n",
103
psio_error(unit, PSIO_ERROR_BLKEND);
105
this_entry->eadd = end_address;
106
this_unit->tocaddress = end_address;
109
/* Update the eadd argument value for the caller */
110
*rel_end = psio_get_address(rel_start, size);
113
/* Now write the actual data to the unit */
114
psio_rw(unit, buffer, address, size, 1);
117
psio_writlen[unit] += size;