11
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.
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
25
int psio_write(unsigned int unit, char *key, char *buffer, ULI size,
26
psio_address rel_start, psio_address *rel_end)
26
psio_address start, psio_address *end)
28
28
psio_ud *this_unit;
29
29
psio_tocentry *this_entry, *last_entry;
30
psio_address address, end_address;
30
psio_address start_toc, start_data, end_data; /* global addresses */
32
34
this_unit = &(psio_unit[unit]);
34
36
/* Find the entry in the TOC */
35
37
this_entry = psio_tocscan(unit, key);
39
tocentry_size = sizeof(psio_tocentry) - 2*sizeof(psio_tocentry *);
37
41
if(this_entry == NULL) { /* New TOC entry */
38
if(rel_start.page||rel_start.offset) psio_error(unit,PSIO_ERROR_BLKSTART);
42
if(start.page||start.offset) psio_error(unit,PSIO_ERROR_BLKSTART);
44
dirty = 1; /* set flag for writing the TOC header */
40
46
this_entry = (psio_tocentry *) malloc(sizeof(psio_tocentry));
41
47
strcpy(this_entry->key,key);
42
48
this_entry->next = NULL;
43
49
this_entry->last = NULL;
45
/* Compute the address of the entry */
51
/* Compute the global address of the new entry */
46
52
if(!(this_unit->toclen)) { /* First TOC entry */
47
53
this_entry->sadd.page = 0;
48
this_entry->sadd.offset = 3*sizeof(ULI);
54
this_entry->sadd.offset = sizeof(ULI); /* offset for the toclen value stored first */
50
55
this_unit->toc = this_entry;
52
57
else { /* Use ending address from last TOC entry */
53
58
last_entry = psio_toclast(unit);
54
59
this_entry->sadd = last_entry->eadd;
56
60
last_entry->next = this_entry;
57
61
this_entry->last = last_entry;
60
/* Data for the write call */
61
address = this_entry->sadd;
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);
63
70
/* Set the end address for this_entry */
64
this_entry->eadd = psio_get_address(this_entry->sadd, size);
71
this_entry->eadd = end_data;
66
73
/* Update the unit's TOC stats */
67
74
this_unit->toclen++;
68
this_unit->tocaddress = this_entry->eadd;
75
psio_wt_toclen(unit, this_unit->toclen);
70
/* Update the rel_end argument value for the caller */
71
*rel_end = psio_get_address(rel_start,size);
77
/* Update end (an entry-relative address) for the caller */
78
*end = psio_get_address(start,size);
73
80
else { /* Old TOC entry */
75
82
/* Compute the global starting page and offset for the block */
76
address = psio_get_global_address(this_entry->sadd, rel_start);
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);
78
87
/* Make sure this block doesn't start past the end of the entry */
79
if(address.page > this_entry->eadd.page)
88
if(start_data.page > this_entry->eadd.page)
80
89
psio_error(unit,PSIO_ERROR_BLKSTART);
81
else if((address.page == this_entry->eadd.page) &&
82
(address.offset > this_entry->eadd.offset))
90
else if((start_data.page == this_entry->eadd.page) &&
91
(start_data.offset > this_entry->eadd.offset))
83
92
psio_error(unit,PSIO_ERROR_BLKSTART);
85
94
/* 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) {
95
end_data = psio_get_address(start_data, size);
96
if(end_data.page > this_entry->eadd.page) {
88
97
if(this_entry->next != NULL) {
89
fprintf(stderr, "PSIO_ERROR: Attempt to write into next entry: %d, %s\n",
98
fprintf(stderr, "PSIO_ERROR: Attempt to write into next entry: %d, %s\n", unit, key);
91
99
psio_error(unit, PSIO_ERROR_BLKEND);
93
this_entry->eadd = end_address;
94
this_unit->tocaddress = end_address;
101
this_entry->eadd = end_data;
102
dirty = 1; /* set flag for writing the TOC header */
97
else if((end_address.page == this_entry->eadd.page) &&
98
(end_address.offset > this_entry->eadd.offset))
104
else if((end_data.page == this_entry->eadd.page) &&
105
(end_data.offset > this_entry->eadd.offset))
100
107
if(this_entry->next != NULL) {
101
fprintf(stderr, "PSIO_ERROR: Attempt to write into next entry: %d, %s\n",
108
fprintf(stderr, "PSIO_ERROR: Attempt to write into next entry: %d, %s\n", unit, key);
103
109
psio_error(unit, PSIO_ERROR_BLKEND);
105
this_entry->eadd = end_address;
106
this_unit->tocaddress = end_address;
111
this_entry->eadd = end_data;
112
dirty = 1; /* set flag for writing the TOC header */
109
/* Update the eadd argument value for the caller */
110
*rel_end = psio_get_address(rel_start, size);
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);
113
122
/* Now write the actual data to the unit */
114
psio_rw(unit, buffer, address, size, 1);
123
psio_rw(unit, buffer, start_data, size, 1);
116
125
#ifdef PSIO_STATS
117
126
psio_writlen[unit] += size;