diff --git a/firmware/common/file.c b/firmware/common/file.c index cb918c6eab..c090c40be5 100644 --- a/firmware/common/file.c +++ b/firmware/common/file.c @@ -1123,6 +1123,44 @@ file_error: return rc; } +int utime(const char *path, const struct utimbuf* times) +{ + DEBUGF("utime(path=\"%s\",times->modtime=%u)\n", path, times->modtime); + + int rc, open1rc = -1; + struct filestr_base pathstr; + struct path_component_info pathinfo; + + file_internal_lock_WRITER(); + + if (!times) + FILE_ERROR(EINVAL, -1); + + open1rc = open_stream_internal(path, FF_ANYTYPE | FF_PARENTINFO, + &pathstr, &pathinfo); + if (open1rc <= 0) + { + DEBUGF("Failed opening path: %d\n", open1rc); + if (open1rc == 0) + FILE_ERROR(ENOENT, -2); + else + FILE_ERROR(ERRNO, open1rc * 10 - 1); + } + + rc = fat_utime(&pathinfo.parentinfo.fatfile, pathstr.fatstr.fatfilep, + times); + if (rc < 0) + { + DEBUGF("I/O error during utime: %d\n", rc); + FILE_ERROR(ERRNO, rc * 10 - 2); + } + +file_error: + if (open1rc >= 0) + close_stream_internal(&pathstr); + file_internal_unlock_WRITER(); + return rc; +} /** Extensions **/ diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c index cc9735d0f7..28d4eb1987 100644 --- a/firmware/drivers/fat.c +++ b/firmware/drivers/fat.c @@ -2276,6 +2276,41 @@ fat_error: return rc; } +int fat_utime(struct fat_file *parent, struct fat_file *file, + const struct utimbuf *times) +{ + struct bpb * const fat_bpb = FAT_BPB(parent->volume); + + if (!fat_bpb) + return -1; + + int rc; + + struct fat_filestr parentstr; + fat_filestr_init(&parentstr, parent); + + dc_lock_cache(); + + union raw_dirent *ent = cache_direntry(fat_bpb, &parentstr, file->e.entry); + if (!ent) + FAT_ERROR(-2); + + uint16_t date; + uint16_t time; + dostime_localtime(times->modtime, &date, &time); + + ent->wrttime = htole16(time); + ent->wrtdate = htole16(date); + ent->lstaccdate = htole16(date); + + dc_dirty_buf(ent); + + rc = 0; +fat_error: + dc_unlock_cache(); + cache_commit(fat_bpb); + return rc; +} /** File stream functions **/ diff --git a/firmware/export/fat.h b/firmware/export/fat.h index 27c2a161f6..b83ceeec0d 100644 --- a/firmware/export/fat.h +++ b/firmware/export/fat.h @@ -140,6 +140,8 @@ enum fat_remove_op /* what should fat_remove(), remove? */ int fat_remove(struct fat_file *file, enum fat_remove_op what); int fat_rename(struct fat_file *parent, struct fat_file *file, const unsigned char *newname); +int fat_utime(struct fat_file *parent, struct fat_file *file, + const struct utimbuf *utimes); /** File stream functions **/ int fat_closewrite(struct fat_filestr *filestr, uint32_t size, diff --git a/firmware/include/file.h b/firmware/include/file.h index 040f48dfc5..f17f14f98e 100644 --- a/firmware/include/file.h +++ b/firmware/include/file.h @@ -85,6 +85,9 @@ int fdprintf(int fildes, const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); #ifndef rename #define rename FS_PREFIX(rename) #endif +#ifndef utime +#define utime FS_PREFIX(utime) +#endif #ifndef filesize #define filesize FS_PREFIX(filesize) #endif diff --git a/firmware/include/filesystem-native.h b/firmware/include/filesystem-native.h index 640e179890..800e7bb23b 100644 --- a/firmware/include/filesystem-native.h +++ b/firmware/include/filesystem-native.h @@ -43,6 +43,8 @@ #define __OPEN_MODE_ARG #define __CREAT_MODE_ARG +#include + int open(const char *name, int oflag); int creat(const char *name); int close(int fildes); @@ -53,6 +55,7 @@ ssize_t read(int fildes, void *buf, size_t nbyte); ssize_t write(int fildes, const void *buf, size_t nbyte); int remove(const char *path); int rename(const char *old, const char *new); +int utime(const char *path, const struct utimbuf* times); off_t filesize(int fildes); int fsamefile(int fildes1, int fildes2); int relate(const char *path1, const char *path2); diff --git a/firmware/libc/include/time.h b/firmware/libc/include/time.h index 4796b8b083..217b454321 100644 --- a/firmware/libc/include/time.h +++ b/firmware/libc/include/time.h @@ -28,6 +28,12 @@ struct tm #if !defined(_TIME_T_DEFINED) && !defined(_TIME_T_DECLARED) typedef long time_t; +struct utimbuf +{ + time_t actime; + time_t modtime; +}; + /* this define below is used by the mingw headers to prevent duplicate typedefs */ #define _TIME_T_DEFINED