mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-22 04:52:39 +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?
|
u8 unk_x38[0x28]; ///< Unknown. Usually zeros?
|
||||||
} PACKED FsSaveDataInfo;
|
} 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 {
|
typedef enum {
|
||||||
ENTRYTYPE_DIR = 0,
|
ENTRYTYPE_DIR = 0,
|
||||||
ENTRYTYPE_FILE = 1
|
ENTRYTYPE_FILE = 1
|
||||||
@ -211,11 +220,12 @@ Result fsFsOpenDirectory(FsFileSystem* fs, const char* path, int flags, FsDir* o
|
|||||||
Result fsFsCommit(FsFileSystem* fs);
|
Result fsFsCommit(FsFileSystem* fs);
|
||||||
Result fsFsGetFreeSpace(FsFileSystem* fs, const char* path, u64* out);
|
Result fsFsGetFreeSpace(FsFileSystem* fs, const char* path, u64* out);
|
||||||
Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out);
|
Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out);
|
||||||
Result fsFsCleanDirectoryRecursively(FsFileSystem* fs, const char* path);
|
Result fsFsGetFileTimeStampRaw(FsFileSystem* fs, const char* path, FsTimeStampRaw *out);/// 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);
|
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);
|
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.
|
/// 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);
|
Result fsFsSetArchiveBit(FsFileSystem* fs, const char *path);
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@ typedef struct
|
|||||||
FsFile fd;
|
FsFile fd;
|
||||||
int flags; /*! Flags used in open(2) */
|
int flags; /*! Flags used in open(2) */
|
||||||
u64 offset; /*! Current file offset */
|
u64 offset; /*! Current file offset */
|
||||||
|
FsTimeStampRaw timestamps;
|
||||||
} fsdev_file_t;
|
} fsdev_file_t;
|
||||||
|
|
||||||
/*! fsdev devoptab */
|
/*! fsdev devoptab */
|
||||||
@ -581,6 +582,10 @@ fsdev_open(struct _reent *r,
|
|||||||
file->fd = fd;
|
file->fd = fd;
|
||||||
file->flags = (flags & (O_ACCMODE|O_APPEND|O_SYNC));
|
file->flags = (flags & (O_ACCMODE|O_APPEND|O_SYNC));
|
||||||
file->offset = 0;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -924,6 +929,14 @@ fsdev_fstat(struct _reent *r,
|
|||||||
st->st_size = (off_t)size;
|
st->st_size = (off_t)size;
|
||||||
st->st_nlink = 1;
|
st->st_nlink = 1;
|
||||||
st->st_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -948,8 +961,10 @@ fsdev_stat(struct _reent *r,
|
|||||||
FsFile fd;
|
FsFile fd;
|
||||||
FsDir fdir;
|
FsDir fdir;
|
||||||
Result rc;
|
Result rc;
|
||||||
|
int ret=0;
|
||||||
char fs_path[FS_MAX_PATH];
|
char fs_path[FS_MAX_PATH];
|
||||||
fsdev_fsdevice *device = NULL;
|
fsdev_fsdevice *device = NULL;
|
||||||
|
FsTimeStampRaw timestamps = {0};
|
||||||
FsEntryType type;
|
FsEntryType type;
|
||||||
|
|
||||||
if(fsdev_getfspath(r, file, &device, fs_path)==-1)
|
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)))
|
if(R_SUCCEEDED(rc = fsFsOpenFile(&device->fs, fs_path, FS_OPEN_READ, &fd)))
|
||||||
{
|
{
|
||||||
fsdev_file_t tmpfd = { .fd = fd };
|
fsdev_file_t tmpfd = { .fd = fd };
|
||||||
rc = fsdev_fstat(r, &tmpfd, st);
|
ret = fsdev_fstat(r, &tmpfd, st);
|
||||||
fsFileClose(&fd);
|
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
|
else
|
||||||
|
@ -975,6 +975,9 @@ Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result fsFsCleanDirectoryRecursively(FsFileSystem* fs, const char* path) {
|
Result fsFsCleanDirectoryRecursively(FsFileSystem* fs, const char* path) {
|
||||||
|
if (!kernelAbove300())
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||||
|
|
||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
ipcAddSendStatic(&c, path, FS_MAX_PATH, 0);
|
||||||
@ -1007,6 +1010,48 @@ Result fsFsCleanDirectoryRecursively(FsFileSystem* fs, const char* path) {
|
|||||||
return rc;
|
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) {
|
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())
|
if (!kernelAbove400())
|
||||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||||
|
Loading…
Reference in New Issue
Block a user