Added support for getting file timestamps via 3.0.0+ fsFsGetFileTimeStampRaw, *stat() timestamps are now set when fsFsGetFileTimeStampRaw is successful. This is now used in fsdev_open() for supporting fstat. The sysver is now checked in fsFsCleanDirectoryRecursively(). Closes #204.

This commit is contained in:
yellows8 2018-11-20 14:22:19 -05:00
parent a7577f7b56
commit 36bed9f8fc
3 changed files with 86 additions and 5 deletions

View File

@ -83,6 +83,15 @@ typedef struct
u8 unk_x38[0x28]; ///< Unknown. Usually zeros?
} PACKED FsSaveDataInfo;
typedef struct
{
u64 created; ///< POSIX timestamp.
u64 modified; ///< POSIX timestamp.
u64 accessed; ///< POSIX timestamp.
u8 is_valid; ///< 0x1 when the timestamps are set.
u8 padding[7];
} PACKED FsTimeStampRaw;
typedef enum {
ENTRYTYPE_DIR = 0,
ENTRYTYPE_FILE = 1
@ -211,11 +220,12 @@ Result fsFsOpenDirectory(FsFileSystem* fs, const char* path, int flags, FsDir* o
Result fsFsCommit(FsFileSystem* fs);
Result fsFsGetFreeSpace(FsFileSystem* fs, const char* path, u64* out);
Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out);
Result fsFsCleanDirectoryRecursively(FsFileSystem* fs, const char* path);
Result fsFsQueryEntry(FsFileSystem* fs, void *out, size_t out_size, const void *in, size_t in_size, const char* path, FsFileSystemQueryType query_type);
Result fsFsGetFileTimeStampRaw(FsFileSystem* fs, const char* path, FsTimeStampRaw *out);/// 3.0.0+
Result fsFsCleanDirectoryRecursively(FsFileSystem* fs, const char* path);/// 3.0.0+
Result fsFsQueryEntry(FsFileSystem* fs, void *out, size_t out_size, const void *in, size_t in_size, const char* path, FsFileSystemQueryType query_type);/// 4.0.0+
void fsFsClose(FsFileSystem* fs);
/// Uses fsFsQueryEntry to set the archive bit on the specified absolute directory path.
/// Uses \ref fsFsQueryEntry to set the archive bit on the specified absolute directory path.
/// This will cause HOS to treat the directory as if it were a file containing the directory's concatenated contents.
Result fsFsSetArchiveBit(FsFileSystem* fs, const char *path);

View File

@ -55,6 +55,7 @@ typedef struct
FsFile fd;
int flags; /*! Flags used in open(2) */
u64 offset; /*! Current file offset */
FsTimeStampRaw timestamps;
} fsdev_file_t;
/*! fsdev devoptab */
@ -581,6 +582,10 @@ fsdev_open(struct _reent *r,
file->fd = fd;
file->flags = (flags & (O_ACCMODE|O_APPEND|O_SYNC));
file->offset = 0;
memset(&file->timestamps, 0, sizeof(file->timestamps));
rc = fsFsGetFileTimeStampRaw(&device->fs, fs_path, &file->timestamps);//Result can be ignored since output is only set on success, etc.
return 0;
}
@ -924,6 +929,14 @@ fsdev_fstat(struct _reent *r,
st->st_size = (off_t)size;
st->st_nlink = 1;
st->st_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
if(file->timestamps.is_valid)
{
st->st_ctime = file->timestamps.created;
st->st_mtime = file->timestamps.modified;
st->st_atime = file->timestamps.accessed;
}
return 0;
}
@ -948,8 +961,10 @@ fsdev_stat(struct _reent *r,
FsFile fd;
FsDir fdir;
Result rc;
int ret=0;
char fs_path[FS_MAX_PATH];
fsdev_fsdevice *device = NULL;
FsTimeStampRaw timestamps = {0};
FsEntryType type;
if(fsdev_getfspath(r, file, &device, fs_path)==-1)
@ -974,10 +989,21 @@ fsdev_stat(struct _reent *r,
if(R_SUCCEEDED(rc = fsFsOpenFile(&device->fs, fs_path, FS_OPEN_READ, &fd)))
{
fsdev_file_t tmpfd = { .fd = fd };
rc = fsdev_fstat(r, &tmpfd, st);
ret = fsdev_fstat(r, &tmpfd, st);
fsFileClose(&fd);
return rc;
if(ret==0)
{
rc = fsFsGetFileTimeStampRaw(&device->fs, fs_path, &timestamps);
if(R_SUCCEEDED(rc) && timestamps.is_valid)
{
st->st_ctime = timestamps.created;
st->st_mtime = timestamps.modified;
st->st_atime = timestamps.accessed;
}
}
return ret;
}
}
else

View File

@ -975,6 +975,9 @@ Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) {
}
Result fsFsCleanDirectoryRecursively(FsFileSystem* fs, const char* path) {
if (!kernelAbove300())
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
IpcCommand c;
ipcInitialize(&c);
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
@ -1007,6 +1010,48 @@ Result fsFsCleanDirectoryRecursively(FsFileSystem* fs, const char* path) {
return rc;
}
Result fsFsGetFileTimeStampRaw(FsFileSystem* fs, const char* path, FsTimeStampRaw *out) {
if (!kernelAbove300())
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
char send_path[FS_MAX_PATH] = {0};
strncpy(send_path, path, sizeof(send_path)-1);
IpcCommand c;
ipcInitialize(&c);
ipcAddSendStatic(&c, send_path, sizeof(send_path), 0);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&fs->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 14;
Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
FsTimeStampRaw out;
} *resp;
serviceIpcParse(&fs->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && out) *out = resp->out;
}
return rc;
}
Result fsFsQueryEntry(FsFileSystem* fs, void *out, size_t out_size, const void *in, size_t in_size, const char* path, FsFileSystemQueryType query_type) {
if (!kernelAbove400())
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);