|
16 | 16 | #include <unistd.h> |
17 | 17 |
|
18 | 18 | #include "ods2_ops.h" |
| 19 | +#include "recfmt.h" |
19 | 20 |
|
20 | 21 | #include "access.h" |
21 | 22 | #include "f11def.h" |
@@ -74,6 +75,24 @@ int ods2_getattr( const char *path, struct stat *st, |
74 | 75 | if( !ods2_rt.force_gid && st->st_gid == 0 ) |
75 | 76 | st->st_gid = getgid(); |
76 | 77 |
|
| 78 | + /* In textmode the on-disk size is wrong (record headers, padding, |
| 79 | + * implicit LFs). Open the file briefly to compute the decoded |
| 80 | + * length; the result is cached, so subsequent stat/read are cheap. |
| 81 | + */ |
| 82 | + if( ods2_rt.textmode && S_ISREG( st->st_mode ) |
| 83 | + && recfmt_textmode_eligible( head ) ) { |
| 84 | + deaccesshead( vioc, NULL, 0 ); |
| 85 | + |
| 86 | + struct FCB *fcb = NULL; |
| 87 | + if( $SUCCESSFUL( accessfile( ods2_vcb, &fid, &fcb, 0 ) ) ) { |
| 88 | + ssize_t lsize = recfmt_logical_size( fcb ); |
| 89 | + if( lsize >= 0 ) |
| 90 | + st->st_size = (off_t)lsize; |
| 91 | + deaccessfile( fcb ); |
| 92 | + } |
| 93 | + return 0; |
| 94 | + } |
| 95 | + |
77 | 96 | deaccesshead( vioc, NULL, 0 ); |
78 | 97 | return 0; |
79 | 98 | } |
@@ -225,6 +244,15 @@ int ods2_read( const char *path, char *out, size_t size, off_t offset, |
225 | 244 | if( fcb == NULL ) |
226 | 245 | return -EBADF; |
227 | 246 |
|
| 247 | + /* In textmode redirect through the record-format decoder; it has |
| 248 | + * its own size accounting and cached buffer. */ |
| 249 | + if( ods2_rt.textmode && fcb->head != NULL |
| 250 | + && recfmt_textmode_eligible( fcb->head ) ) { |
| 251 | + ssize_t n = recfmt_read( fcb, offset, out, size ); |
| 252 | + if( n < 0 ) return -EIO; |
| 253 | + return (int)n; |
| 254 | + } |
| 255 | + |
228 | 256 | /* Logical end of file derived from the RECATTR. EOF block is the |
229 | 257 | * first block past the last block holding data; ffb is the count |
230 | 258 | * of bytes used in the last block. When efblk == 0 the file has |
|
0 commit comments