1 |
|
|
/* $OpenBSD: cd9660_write.c,v 1.8 2017/04/06 19:09:45 natano Exp $ */ |
2 |
|
|
/* $NetBSD: cd9660_write.c,v 1.17 2013/10/19 17:16:37 christos Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan |
6 |
|
|
* Perez-Rathke and Ram Vedam. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, |
9 |
|
|
* Alan Perez-Rathke and Ram Vedam. |
10 |
|
|
* |
11 |
|
|
* Redistribution and use in source and binary forms, with or |
12 |
|
|
* without modification, are permitted provided that the following |
13 |
|
|
* conditions are met: |
14 |
|
|
* 1. Redistributions of source code must retain the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer. |
16 |
|
|
* 2. Redistributions in binary form must reproduce the above |
17 |
|
|
* copyright notice, this list of conditions and the following |
18 |
|
|
* disclaimer in the documentation and/or other materials provided |
19 |
|
|
* with the distribution. |
20 |
|
|
* |
21 |
|
|
* THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN |
22 |
|
|
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR |
23 |
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
24 |
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
25 |
|
|
* DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN |
26 |
|
|
* GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT, |
27 |
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
28 |
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
29 |
|
|
* USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
30 |
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
31 |
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
33 |
|
|
* OF SUCH DAMAGE. |
34 |
|
|
*/ |
35 |
|
|
|
36 |
|
|
#include "cd9660.h" |
37 |
|
|
#include "iso9660_rrip.h" |
38 |
|
|
|
39 |
|
|
static int cd9660_write_volume_descriptors(iso9660_disk *, FILE *); |
40 |
|
|
static int cd9660_write_path_table(iso9660_disk *, FILE *, off_t, int); |
41 |
|
|
static int cd9660_write_path_tables(iso9660_disk *, FILE *); |
42 |
|
|
static int cd9660_write_file(iso9660_disk *, FILE *, cd9660node *); |
43 |
|
|
static int cd9660_write_filedata(iso9660_disk *, FILE *, off_t, |
44 |
|
|
const unsigned char *, int); |
45 |
|
|
#if 0 |
46 |
|
|
static int cd9660_write_buffered(FILE *, off_t, int, const unsigned char *); |
47 |
|
|
#endif |
48 |
|
|
static void cd9660_write_rr(iso9660_disk *, FILE *, cd9660node *, off_t, off_t); |
49 |
|
|
|
50 |
|
|
/* |
51 |
|
|
* Write the image |
52 |
|
|
* Writes the entire image |
53 |
|
|
* @param const char* The filename for the image |
54 |
|
|
* @returns int 1 on success, 0 on failure |
55 |
|
|
*/ |
56 |
|
|
int |
57 |
|
|
cd9660_write_image(iso9660_disk *diskStructure, const char* image) |
58 |
|
|
{ |
59 |
|
|
FILE *fd; |
60 |
|
|
int status; |
61 |
|
|
char buf[CD9660_SECTOR_SIZE]; |
62 |
|
|
|
63 |
|
|
if ((fd = fopen(image, "w+")) == NULL) |
64 |
|
|
err(1, "%s: Can't open `%s' for writing", __func__, image); |
65 |
|
|
|
66 |
|
|
if (diskStructure->has_generic_bootimage) { |
67 |
|
|
status = cd9660_copy_file(diskStructure, fd, 0, |
68 |
|
|
diskStructure->generic_bootimage); |
69 |
|
|
if (status == 0) { |
70 |
|
|
warnx("%s: Error writing generic boot image", |
71 |
|
|
__func__); |
72 |
|
|
goto cleanup_bad_image; |
73 |
|
|
} |
74 |
|
|
} |
75 |
|
|
|
76 |
|
|
/* Write the volume descriptors */ |
77 |
|
|
status = cd9660_write_volume_descriptors(diskStructure, fd); |
78 |
|
|
if (status == 0) { |
79 |
|
|
warnx("%s: Error writing volume descriptors to image", |
80 |
|
|
__func__); |
81 |
|
|
goto cleanup_bad_image; |
82 |
|
|
} |
83 |
|
|
|
84 |
|
|
/* |
85 |
|
|
* Write the path tables: there are actually four, but right |
86 |
|
|
* now we are only concearned with two. |
87 |
|
|
*/ |
88 |
|
|
status = cd9660_write_path_tables(diskStructure, fd); |
89 |
|
|
if (status == 0) { |
90 |
|
|
warnx("%s: Error writing path tables to image", __func__); |
91 |
|
|
goto cleanup_bad_image; |
92 |
|
|
} |
93 |
|
|
|
94 |
|
|
/* Write the directories and files */ |
95 |
|
|
status = cd9660_write_file(diskStructure, fd, diskStructure->rootNode); |
96 |
|
|
if (status == 0) { |
97 |
|
|
warnx("%s: Error writing files to image", __func__); |
98 |
|
|
goto cleanup_bad_image; |
99 |
|
|
} |
100 |
|
|
|
101 |
|
|
if (diskStructure->is_bootable) { |
102 |
|
|
cd9660_write_boot(diskStructure, fd); |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
/* Write padding bits. This is temporary */ |
106 |
|
|
memset(buf, 0, CD9660_SECTOR_SIZE); |
107 |
|
|
cd9660_write_filedata(diskStructure, fd, |
108 |
|
|
diskStructure->totalSectors - 1, buf, 1); |
109 |
|
|
|
110 |
|
|
fclose(fd); |
111 |
|
|
return 1; |
112 |
|
|
|
113 |
|
|
cleanup_bad_image: |
114 |
|
|
fclose(fd); |
115 |
|
|
unlink(image); |
116 |
|
|
return 0; |
117 |
|
|
} |
118 |
|
|
|
119 |
|
|
static int |
120 |
|
|
cd9660_write_volume_descriptors(iso9660_disk *diskStructure, FILE *fd) |
121 |
|
|
{ |
122 |
|
|
volume_descriptor *vd_temp = diskStructure->firstVolumeDescriptor; |
123 |
|
|
while (vd_temp != NULL) { |
124 |
|
|
cd9660_write_filedata(diskStructure, fd, vd_temp->sector, |
125 |
|
|
vd_temp->volumeDescriptorData, 1); |
126 |
|
|
vd_temp = vd_temp->next; |
127 |
|
|
} |
128 |
|
|
return 1; |
129 |
|
|
} |
130 |
|
|
|
131 |
|
|
/* |
132 |
|
|
* Write out an individual path table |
133 |
|
|
* Used just to keep redundant code to a minimum |
134 |
|
|
* @param FILE *fd Valid file pointer |
135 |
|
|
* @param int Sector to start writing path table to |
136 |
|
|
* @param int Endian mode : BIG_ENDIAN or LITTLE_ENDIAN |
137 |
|
|
* @returns int 1 on success, 0 on failure |
138 |
|
|
*/ |
139 |
|
|
static int |
140 |
|
|
cd9660_write_path_table(iso9660_disk *diskStructure, FILE *fd, off_t sector, |
141 |
|
|
int mode) |
142 |
|
|
{ |
143 |
|
|
int path_table_sectors = CD9660_BLOCKS(diskStructure->sectorSize, |
144 |
|
|
diskStructure->pathTableLength); |
145 |
|
|
unsigned char *buffer; |
146 |
|
|
unsigned char *buffer_head; |
147 |
|
|
int len; |
148 |
|
|
path_table_entry temp_entry; |
149 |
|
|
cd9660node *ptcur; |
150 |
|
|
|
151 |
|
|
buffer = ecalloc(path_table_sectors, diskStructure->sectorSize); |
152 |
|
|
buffer_head = buffer; |
153 |
|
|
|
154 |
|
|
ptcur = diskStructure->rootNode; |
155 |
|
|
|
156 |
|
|
while (ptcur != NULL) { |
157 |
|
|
memset(&temp_entry, 0, sizeof(path_table_entry)); |
158 |
|
|
temp_entry.length[0] = ptcur->isoDirRecord->name_len[0]; |
159 |
|
|
temp_entry.extended_attribute_length[0] = |
160 |
|
|
ptcur->isoDirRecord->ext_attr_length[0]; |
161 |
|
|
memcpy(temp_entry.name, ptcur->isoDirRecord->name, |
162 |
|
|
temp_entry.length[0] + 1); |
163 |
|
|
|
164 |
|
|
/* round up */ |
165 |
|
|
len = temp_entry.length[0] + 8 + (temp_entry.length[0] & 0x01); |
166 |
|
|
|
167 |
|
|
/* todo: function pointers instead */ |
168 |
|
|
if (mode == LITTLE_ENDIAN) { |
169 |
|
|
cd9660_731(ptcur->fileDataSector, |
170 |
|
|
temp_entry.first_sector); |
171 |
|
|
cd9660_721((ptcur->parent == NULL ? |
172 |
|
|
1 : ptcur->parent->ptnumber), |
173 |
|
|
temp_entry.parent_number); |
174 |
|
|
} else { |
175 |
|
|
cd9660_732(ptcur->fileDataSector, |
176 |
|
|
temp_entry.first_sector); |
177 |
|
|
cd9660_722((ptcur->parent == NULL ? |
178 |
|
|
1 : ptcur->parent->ptnumber), |
179 |
|
|
temp_entry.parent_number); |
180 |
|
|
} |
181 |
|
|
|
182 |
|
|
|
183 |
|
|
memcpy(buffer, &temp_entry, len); |
184 |
|
|
buffer += len; |
185 |
|
|
|
186 |
|
|
ptcur = ptcur->ptnext; |
187 |
|
|
} |
188 |
|
|
|
189 |
|
|
return cd9660_write_filedata(diskStructure, fd, sector, buffer_head, |
190 |
|
|
path_table_sectors); |
191 |
|
|
} |
192 |
|
|
|
193 |
|
|
|
194 |
|
|
/* |
195 |
|
|
* Write out the path tables to disk |
196 |
|
|
* Each file descriptor should be pointed to by the PVD, so we know which |
197 |
|
|
* sector to copy them to. One thing to watch out for: the only path tables |
198 |
|
|
* stored are in the endian mode that the application is compiled for. So, |
199 |
|
|
* the first thing to do is write out that path table, then to write the one |
200 |
|
|
* in the other endian mode requires to convert the endianness of each entry |
201 |
|
|
* in the table. The best way to do this would be to create a temporary |
202 |
|
|
* path_table_entry structure, then for each path table entry, copy it to |
203 |
|
|
* the temporary entry, translate, then copy that to disk. |
204 |
|
|
* |
205 |
|
|
* @param FILE* Valid file descriptor |
206 |
|
|
* @returns int 0 on failure, 1 on success |
207 |
|
|
*/ |
208 |
|
|
static int |
209 |
|
|
cd9660_write_path_tables(iso9660_disk *diskStructure, FILE *fd) |
210 |
|
|
{ |
211 |
|
|
if (cd9660_write_path_table(diskStructure, fd, |
212 |
|
|
diskStructure->primaryLittleEndianTableSector, LITTLE_ENDIAN) == 0) |
213 |
|
|
return 0; |
214 |
|
|
|
215 |
|
|
if (cd9660_write_path_table(diskStructure, fd, |
216 |
|
|
diskStructure->primaryBigEndianTableSector, BIG_ENDIAN) == 0) |
217 |
|
|
return 0; |
218 |
|
|
|
219 |
|
|
/* @TODO: handle remaining two path tables */ |
220 |
|
|
return 1; |
221 |
|
|
} |
222 |
|
|
|
223 |
|
|
/* |
224 |
|
|
* Write a file to disk |
225 |
|
|
* Writes a file, its directory record, and its data to disk |
226 |
|
|
* This file is designed to be called RECURSIVELY, so initially call it |
227 |
|
|
* with the root node. All of the records should store what sector the |
228 |
|
|
* file goes in, so no computation should be necessary. |
229 |
|
|
* |
230 |
|
|
* @param int fd Valid file descriptor |
231 |
|
|
* @param struct cd9660node* writenode Pointer to the file to be written |
232 |
|
|
* @returns int 0 on failure, 1 on success |
233 |
|
|
*/ |
234 |
|
|
static int |
235 |
|
|
cd9660_write_file(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode) |
236 |
|
|
{ |
237 |
|
|
char *temp_file_name; |
238 |
|
|
off_t working_sector; |
239 |
|
|
int cur_sector_offset; |
240 |
|
|
iso_directory_record_cd9660 temp_record; |
241 |
|
|
cd9660node *temp; |
242 |
|
|
|
243 |
|
|
/* Todo : clean up variables */ |
244 |
|
|
|
245 |
|
|
if ((writenode->level != 0) && |
246 |
|
|
!(writenode->node->type & S_IFDIR)) { |
247 |
|
|
fsinode *inode = writenode->node->inode; |
248 |
|
|
/* Only attempt to write unwritten files that have length. */ |
249 |
|
|
if ((inode->flags & FI_WRITTEN) != 0) { |
250 |
|
|
INODE_WARNX(("%s: skipping written inode %d", __func__, |
251 |
|
|
(int)inode->st.st_ino)); |
252 |
|
|
} else if (writenode->fileDataLength > 0) { |
253 |
|
|
INODE_WARNX(("%s: writing inode %d blocks at %" PRIu32, |
254 |
|
|
__func__, (int)inode->st.st_ino, inode->ino)); |
255 |
|
|
inode->flags |= FI_WRITTEN; |
256 |
|
|
temp_file_name = cd9660_compute_full_filename(writenode); |
257 |
|
|
if (temp_file_name == NULL) |
258 |
|
|
return 0; |
259 |
|
|
if (cd9660_copy_file(diskStructure, fd, |
260 |
|
|
writenode->fileDataSector, temp_file_name) == 0) |
261 |
|
|
return 0; |
262 |
|
|
} |
263 |
|
|
} else { |
264 |
|
|
/* |
265 |
|
|
* Here is a new revelation that ECMA didnt explain |
266 |
|
|
* (at least not well). |
267 |
|
|
* ALL . and .. records store the name "\0" and "\1" |
268 |
|
|
* resepctively. So, for each directory, we have to |
269 |
|
|
* make a new node. |
270 |
|
|
* |
271 |
|
|
* This is where it gets kinda messy, since we have to |
272 |
|
|
* be careful of sector boundaries |
273 |
|
|
*/ |
274 |
|
|
cur_sector_offset = 0; |
275 |
|
|
working_sector = writenode->fileDataSector; |
276 |
|
|
if (fseeko(fd, working_sector * diskStructure->sectorSize, |
277 |
|
|
SEEK_SET) == -1) |
278 |
|
|
err(1, "fseeko"); |
279 |
|
|
|
280 |
|
|
/* |
281 |
|
|
* Now loop over children, writing out their directory |
282 |
|
|
* records - beware of sector boundaries |
283 |
|
|
*/ |
284 |
|
|
TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) { |
285 |
|
|
/* |
286 |
|
|
* Copy the temporary record and adjust its size |
287 |
|
|
* if necessary |
288 |
|
|
*/ |
289 |
|
|
memcpy(&temp_record, temp->isoDirRecord, |
290 |
|
|
sizeof(iso_directory_record_cd9660)); |
291 |
|
|
|
292 |
|
|
temp_record.length[0] = |
293 |
|
|
cd9660_compute_record_size(diskStructure, temp); |
294 |
|
|
|
295 |
|
|
if (temp_record.length[0] + cur_sector_offset >= |
296 |
|
|
diskStructure->sectorSize) { |
297 |
|
|
cur_sector_offset = 0; |
298 |
|
|
working_sector++; |
299 |
|
|
|
300 |
|
|
/* Seek to the next sector. */ |
301 |
|
|
if (fseeko(fd, working_sector * |
302 |
|
|
diskStructure->sectorSize, SEEK_SET) == -1) |
303 |
|
|
err(1, "fseeko"); |
304 |
|
|
} |
305 |
|
|
/* Write out the basic ISO directory record */ |
306 |
|
|
(void)fwrite(&temp_record, 1, |
307 |
|
|
temp->isoDirRecord->length[0], fd); |
308 |
|
|
if (diskStructure->rock_ridge_enabled) { |
309 |
|
|
cd9660_write_rr(diskStructure, fd, temp, |
310 |
|
|
cur_sector_offset, working_sector); |
311 |
|
|
} |
312 |
|
|
if (fseeko(fd, working_sector * |
313 |
|
|
diskStructure->sectorSize + cur_sector_offset + |
314 |
|
|
temp_record.length[0] - temp->su_tail_size, |
315 |
|
|
SEEK_SET) == -1) |
316 |
|
|
err(1, "fseeko"); |
317 |
|
|
if (temp->su_tail_size > 0) |
318 |
|
|
fwrite(temp->su_tail_data, 1, |
319 |
|
|
temp->su_tail_size, fd); |
320 |
|
|
if (ferror(fd)) { |
321 |
|
|
warnx("%s: write error", __func__); |
322 |
|
|
return 0; |
323 |
|
|
} |
324 |
|
|
cur_sector_offset += temp_record.length[0]; |
325 |
|
|
|
326 |
|
|
} |
327 |
|
|
|
328 |
|
|
/* |
329 |
|
|
* Recurse on children. |
330 |
|
|
*/ |
331 |
|
|
TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) { |
332 |
|
|
if (cd9660_write_file(diskStructure, fd, temp) == 0) |
333 |
|
|
return 0; |
334 |
|
|
} |
335 |
|
|
} |
336 |
|
|
return 1; |
337 |
|
|
} |
338 |
|
|
|
339 |
|
|
/* |
340 |
|
|
* Wrapper function to write a buffer (one sector) to disk. |
341 |
|
|
* Seeks and writes the buffer. |
342 |
|
|
* NOTE: You dont NEED to use this function, but it might make your |
343 |
|
|
* life easier if you have to write things that align to a sector |
344 |
|
|
* (such as volume descriptors). |
345 |
|
|
* |
346 |
|
|
* @param int fd Valid file descriptor |
347 |
|
|
* @param int sector Sector number to write to |
348 |
|
|
* @param const unsigned char* Buffer to write. This should be the |
349 |
|
|
* size of a sector, and if only a portion |
350 |
|
|
* is written, the rest should be set to 0. |
351 |
|
|
*/ |
352 |
|
|
static int |
353 |
|
|
cd9660_write_filedata(iso9660_disk *diskStructure, FILE *fd, off_t sector, |
354 |
|
|
const unsigned char *buf, int numsecs) |
355 |
|
|
{ |
356 |
|
|
off_t curpos; |
357 |
|
|
size_t success; |
358 |
|
|
|
359 |
|
|
curpos = ftello(fd); |
360 |
|
|
|
361 |
|
|
if (fseeko(fd, sector * diskStructure->sectorSize, SEEK_SET) == -1) |
362 |
|
|
err(1, "fseeko"); |
363 |
|
|
|
364 |
|
|
success = fwrite(buf, diskStructure->sectorSize * numsecs, 1, fd); |
365 |
|
|
|
366 |
|
|
if (fseeko(fd, curpos, SEEK_SET) == -1) |
367 |
|
|
err(1, "fseeko"); |
368 |
|
|
|
369 |
|
|
if (success == 1) |
370 |
|
|
success = diskStructure->sectorSize * numsecs; |
371 |
|
|
return success; |
372 |
|
|
} |
373 |
|
|
|
374 |
|
|
#if 0 |
375 |
|
|
static int |
376 |
|
|
cd9660_write_buffered(FILE *fd, off_t offset, int buff_len, |
377 |
|
|
const unsigned char* buffer) |
378 |
|
|
{ |
379 |
|
|
static int working_sector = -1; |
380 |
|
|
static char buf[CD9660_SECTOR_SIZE]; |
381 |
|
|
|
382 |
|
|
return 0; |
383 |
|
|
} |
384 |
|
|
#endif |
385 |
|
|
|
386 |
|
|
int |
387 |
|
|
cd9660_copy_file(iso9660_disk *diskStructure, FILE *fd, off_t start_sector, |
388 |
|
|
const char *filename) |
389 |
|
|
{ |
390 |
|
|
FILE *rf; |
391 |
|
|
int bytes_read; |
392 |
|
|
off_t sector = start_sector; |
393 |
|
|
int buf_size = diskStructure->sectorSize; |
394 |
|
|
char *buf; |
395 |
|
|
|
396 |
|
|
buf = emalloc(buf_size); |
397 |
|
|
if ((rf = fopen(filename, "rb")) == NULL) { |
398 |
|
|
warn("%s: cannot open %s", __func__, filename); |
399 |
|
|
free(buf); |
400 |
|
|
return 0; |
401 |
|
|
} |
402 |
|
|
|
403 |
|
|
if (fseeko(fd, start_sector * diskStructure->sectorSize, SEEK_SET) == -1) |
404 |
|
|
err(1, "fseeko"); |
405 |
|
|
|
406 |
|
|
while (!feof(rf)) { |
407 |
|
|
bytes_read = fread(buf,1,buf_size,rf); |
408 |
|
|
if (ferror(rf)) { |
409 |
|
|
warn("%s: fread", __func__); |
410 |
|
|
free(buf); |
411 |
|
|
(void)fclose(rf); |
412 |
|
|
return 0; |
413 |
|
|
} |
414 |
|
|
|
415 |
|
|
fwrite(buf,1,bytes_read,fd); |
416 |
|
|
if (ferror(fd)) { |
417 |
|
|
warn("%s: fwrite", __func__); |
418 |
|
|
free(buf); |
419 |
|
|
(void)fclose(rf); |
420 |
|
|
return 0; |
421 |
|
|
} |
422 |
|
|
sector++; |
423 |
|
|
} |
424 |
|
|
|
425 |
|
|
fclose(rf); |
426 |
|
|
free(buf); |
427 |
|
|
return 1; |
428 |
|
|
} |
429 |
|
|
|
430 |
|
|
static void |
431 |
|
|
cd9660_write_rr(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode, |
432 |
|
|
off_t offset, off_t sector) |
433 |
|
|
{ |
434 |
|
|
int in_ca = 0; |
435 |
|
|
struct ISO_SUSP_ATTRIBUTES *myattr; |
436 |
|
|
|
437 |
|
|
offset += writenode->isoDirRecord->length[0]; |
438 |
|
|
if (fseeko(fd, sector * diskStructure->sectorSize + offset, SEEK_SET) == |
439 |
|
|
-1) |
440 |
|
|
err(1, "fseeko"); |
441 |
|
|
/* Offset now points at the end of the record */ |
442 |
|
|
TAILQ_FOREACH(myattr, &writenode->head, rr_ll) { |
443 |
|
|
fwrite(&(myattr->attr), CD9660_SUSP_ENTRY_SIZE(myattr), 1, fd); |
444 |
|
|
|
445 |
|
|
if (!in_ca) { |
446 |
|
|
offset += CD9660_SUSP_ENTRY_SIZE(myattr); |
447 |
|
|
if (myattr->last_in_suf) { |
448 |
|
|
/* |
449 |
|
|
* Point the offset to the start of this |
450 |
|
|
* record's CE area |
451 |
|
|
*/ |
452 |
|
|
if (fseeko(fd, ((off_t)diskStructure-> |
453 |
|
|
susp_continuation_area_start_sector * |
454 |
|
|
diskStructure->sectorSize) |
455 |
|
|
+ writenode->susp_entry_ce_start, |
456 |
|
|
SEEK_SET) == -1) |
457 |
|
|
err(1, "fseeko"); |
458 |
|
|
in_ca = 1; |
459 |
|
|
} |
460 |
|
|
} |
461 |
|
|
} |
462 |
|
|
|
463 |
|
|
/* |
464 |
|
|
* If we had to go to the continuation area, head back to |
465 |
|
|
* where we should be. |
466 |
|
|
*/ |
467 |
|
|
if (in_ca) |
468 |
|
|
if (fseeko(fd, sector * diskStructure->sectorSize + offset, |
469 |
|
|
SEEK_SET) == -1) |
470 |
|
|
err(1, "fseeko"); |
471 |
|
|
} |