summaryrefslogtreecommitdiff
path: root/firmware/common/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/common/file.c')
-rw-r--r--firmware/common/file.c57
1 files changed, 33 insertions, 24 deletions
diff --git a/firmware/common/file.c b/firmware/common/file.c
index 6444918f1b..1f93824dc8 100644
--- a/firmware/common/file.c
+++ b/firmware/common/file.c
@@ -54,7 +54,7 @@ static struct filestr_desc * get_filestr(int fildes)
54 return file; 54 return file;
55 55
56 DEBUGF("fildes %d: bad file number\n", fildes); 56 DEBUGF("fildes %d: bad file number\n", fildes);
57 errno = (file && file->stream.flags == FV_NONEXIST) ? ENXIO : EBADF; 57 errno = (file && (file->stream.flags & FD_NONEXIST)) ? ENXIO : EBADF;
58 return NULL; 58 return NULL;
59} 59}
60 60
@@ -187,24 +187,28 @@ file_error:
187 return rc; 187 return rc;
188} 188}
189 189
190/* callback for each file stream to make sure all data is in sync with new 190/* Handle syncing all file's streams to the truncation */
191 size */ 191static void handle_truncate(struct filestr_desc * const file, file_size_t size)
192void ftruncate_internal_callback(struct filestr_base *stream,
193 struct filestr_base *s)
194{ 192{
195 struct filestr_desc *file = (struct filestr_desc *)s; 193 unsigned long filesectors = filesize_sectors(size);
196 file_size_t size = *file->sizep;
197
198 /* caches with data beyond new extents are invalid */
199 unsigned long sector = file->stream.cachep->sector;
200 if (sector != INVALID_SECNUM && sector >= filesize_sectors(size))
201 filestr_discard_cache(&file->stream);
202 194
203 /* keep all positions within bounds */ 195 struct filestr_base *s = NULL;
204 if (file->offset > size) 196 while ((s = fileobj_get_next_stream(&file->stream, s)))
205 file->offset = size; 197 {
206 198 /* caches with data beyond new extents are invalid */
207 (void)stream; 199 unsigned long sector = s->cachep->sector;
200 if (sector != INVALID_SECNUM && sector >= filesectors)
201 filestr_discard_cache(s);
202
203 /* files outside bounds must be rewound */
204 if (fat_query_sectornum(&s->fatstr) > filesectors)
205 fat_seek_to_stream(&s->fatstr, &file->stream.fatstr);
206
207 /* clip file offset too if needed */
208 struct filestr_desc *f = (struct filestr_desc *)s;
209 if (f->offset > size)
210 f->offset = size;
211 }
208} 212}
209 213
210/* truncate the file to the specified length */ 214/* truncate the file to the specified length */
@@ -246,13 +250,17 @@ static int ftruncate_internal(struct filestr_desc *file, file_size_t size,
246 rc2 = fat_truncate(&file->stream.fatstr); 250 rc2 = fat_truncate(&file->stream.fatstr);
247 if (rc2 < 0) 251 if (rc2 < 0)
248 FILE_ERROR(EIO, rc2 * 10 - 3); 252 FILE_ERROR(EIO, rc2 * 10 - 3);
253
254 /* never needs to be done this way again since any data beyond the
255 cached size is now gone */
256 fileobj_change_flags(&file->stream, 0, FO_TRUNC);
249 } 257 }
250 /* else just change the cached file size */ 258 /* else just change the cached file size */
251 259
252 if (truncsize < cursize) 260 if (truncsize < cursize)
253 { 261 {
254 *file->sizep = truncsize; 262 *file->sizep = truncsize;
255 fileop_ontruncate_internal(&file->stream); 263 handle_truncate(file, truncsize);
256 } 264 }
257 265
258 /* if truncation was partially successful, it effectively destroyed 266 /* if truncation was partially successful, it effectively destroyed
@@ -299,10 +307,6 @@ static int fsync_internal(struct filestr_desc *file)
299 int rc2 = ftruncate_internal(file, size, rc == 0); 307 int rc2 = ftruncate_internal(file, size, rc == 0);
300 if (rc2 < 0) 308 if (rc2 < 0)
301 FILE_ERROR(ERRNO, rc2 * 10 - 2); 309 FILE_ERROR(ERRNO, rc2 * 10 - 2);
302
303 /* never needs to be done this way again since any data beyond the
304 cached size is now gone */
305 fileobj_change_flags(&file->stream, 0, FO_TRUNC);
306 } 310 }
307 311
308file_error:; 312file_error:;
@@ -327,8 +331,7 @@ static int close_internal(struct filestr_desc *file)
327 /* call only when holding WRITER lock (updates directory entries) */ 331 /* call only when holding WRITER lock (updates directory entries) */
328 int rc; 332 int rc;
329 333
330 if ((file->stream.flags & FD_WRITE) && 334 if ((file->stream.flags & (FD_WRITE|FD_NONEXIST)) == FD_WRITE)
331 !(fileobj_get_flags(&file->stream) & FO_REMOVED))
332 { 335 {
333 rc = fsync_internal(file); 336 rc = fsync_internal(file);
334 if (rc < 0) 337 if (rc < 0)
@@ -786,6 +789,12 @@ int open_noiso_internal(const char *path, int oflag)
786 return open_internal_locked(path, oflag, FF_ANYTYPE | FF_NOISO); 789 return open_internal_locked(path, oflag, FF_ANYTYPE | FF_NOISO);
787} 790}
788 791
792void force_close_writer_internal(struct filestr_base *stream)
793{
794 /* only we do writers so we know this is our guy */
795 close_internal((struct filestr_desc *)stream);
796}
797
789 798
790/** POSIX **/ 799/** POSIX **/
791 800