mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 20:42:44 +02:00
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:
parent
a7577f7b56
commit
36bed9f8fc
@ -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);
|
||||
|
||||
|
@ -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, ×tamps);
|
||||
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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user