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 start = The entry-relative starting page/offset to write the data.
19
** \param end = 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 start, psio_address *end)
29
psio_tocentry *this_entry, *last_entry;
30
psio_address start_toc, start_data, end_data; /* global addresses */
34
this_unit = &(psio_unit[unit]);
36
/* Find the entry in the TOC */
37
this_entry = psio_tocscan(unit, key);
39
tocentry_size = sizeof(psio_tocentry) - 2*sizeof(psio_tocentry *);
41
if(this_entry == NULL) { /* New TOC entry */
42
if(start.page||start.offset) psio_error(unit,PSIO_ERROR_BLKSTART);
44
dirty = 1; /* set flag for writing the TOC header */
46
this_entry = (psio_tocentry *) malloc(sizeof(psio_tocentry));
47
strcpy(this_entry->key,key);
48
this_entry->next = NULL;
49
this_entry->last = NULL;
51
/* Compute the global address of the new entry */
52
if(!(this_unit->toclen)) { /* First TOC entry */
53
this_entry->sadd.page = 0;
54
this_entry->sadd.offset = sizeof(ULI); /* offset for the toclen value stored first */
55
this_unit->toc = this_entry;
57
else { /* Use ending address from last TOC entry */
58
last_entry = psio_toclast(unit);
59
this_entry->sadd = last_entry->eadd;
60
last_entry->next = this_entry;
61
this_entry->last = last_entry;
64
/* compute important global addresses for the entry */
65
start_toc = this_entry->sadd;
66
start_data = psio_get_address(start_toc, tocentry_size);
67
start_data = psio_get_global_address(start_data, start);
68
end_data = psio_get_address(start_data, size);
70
/* Set the end address for this_entry */
71
this_entry->eadd = end_data;
73
/* Update the unit's TOC stats */
75
psio_wt_toclen(unit, this_unit->toclen);
77
/* Update end (an entry-relative address) for the caller */
78
*end = psio_get_address(start,size);
80
else { /* Old TOC entry */
82
/* Compute the global starting page and offset for the block */
83
start_toc = this_entry->sadd;
84
start_data = psio_get_address(start_toc, tocentry_size);
85
start_data = psio_get_global_address(start_data, start);
87
/* Make sure this block doesn't start past the end of the entry */
88
if(start_data.page > this_entry->eadd.page)
89
psio_error(unit,PSIO_ERROR_BLKSTART);
90
else if((start_data.page == this_entry->eadd.page) &&
91
(start_data.offset > this_entry->eadd.offset))
92
psio_error(unit,PSIO_ERROR_BLKSTART);
94
/* Compute the new global ending address for the entry, if necessary */
95
end_data = psio_get_address(start_data, size);
96
if(end_data.page > this_entry->eadd.page) {
97
if(this_entry->next != NULL) {
98
fprintf(stderr, "PSIO_ERROR: Attempt to write into next entry: %d, %s\n", unit, key);
99
psio_error(unit, PSIO_ERROR_BLKEND);
101
this_entry->eadd = end_data;
102
dirty = 1; /* set flag for writing the TOC header */
104
else if((end_data.page == this_entry->eadd.page) &&
105
(end_data.offset > this_entry->eadd.offset))
107
if(this_entry->next != NULL) {
108
fprintf(stderr, "PSIO_ERROR: Attempt to write into next entry: %d, %s\n", unit, key);
109
psio_error(unit, PSIO_ERROR_BLKEND);
111
this_entry->eadd = end_data;
112
dirty = 1; /* set flag for writing the TOC header */
115
/* Update end (an entry-relative address) for the caller */
116
*end = psio_get_address(start, size);
119
if(dirty) /* Need to first write/update the TOC header for this record */
120
psio_rw(unit, (char *) this_entry, start_toc, tocentry_size, 1);
122
/* Now write the actual data to the unit */
123
psio_rw(unit, buffer, start_data, size, 1);
126
psio_writlen[unit] += size;