summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar wwylele2016-10-17 14:54:48 +0800
committerGravatar wwylele2016-11-19 17:17:19 +0200
commit7166fdc49072d987d04e681de4d9e1558ba75c63 (patch)
treeb65665c71cc0fb5dfff8ba64d1a64898ec8571fd /src
parentFileSys: remove Open from FileBackend (diff)
downloadyuzu-7166fdc49072d987d04e681de4d9e1558ba75c63.tar.gz
yuzu-7166fdc49072d987d04e681de4d9e1558ba75c63.tar.xz
yuzu-7166fdc49072d987d04e681de4d9e1558ba75c63.zip
FileSys: add SaveDataArchive
The error checking of SaveDataArchive is completely different from DiskArchive, so it has to be a new class instead of a subclass of DiskArchive.
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/file_sys/archive_savedata.cpp4
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp4
-rw-r--r--src/core/file_sys/errors.h29
-rw-r--r--src/core/file_sys/savedata_archive.cpp283
-rw-r--r--src/core/file_sys/savedata_archive.h43
-rw-r--r--src/core/hle/result.h7
7 files changed, 368 insertions, 4 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index ae9e8dcea..63a402ad0 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -25,6 +25,7 @@ set(SRCS
25 file_sys/disk_archive.cpp 25 file_sys/disk_archive.cpp
26 file_sys/ivfc_archive.cpp 26 file_sys/ivfc_archive.cpp
27 file_sys/path_parser.cpp 27 file_sys/path_parser.cpp
28 file_sys/savedata_archive.cpp
28 gdbstub/gdbstub.cpp 29 gdbstub/gdbstub.cpp
29 hle/config_mem.cpp 30 hle/config_mem.cpp
30 hle/hle.cpp 31 hle/hle.cpp
@@ -170,6 +171,7 @@ set(HEADERS
170 file_sys/file_backend.h 171 file_sys/file_backend.h
171 file_sys/ivfc_archive.h 172 file_sys/ivfc_archive.h
172 file_sys/path_parser.h 173 file_sys/path_parser.h
174 file_sys/savedata_archive.h
173 gdbstub/gdbstub.h 175 gdbstub/gdbstub.h
174 hle/config_mem.h 176 hle/config_mem.h
175 hle/function_wrappers.h 177 hle/function_wrappers.h
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index 6711035ec..ecb44a215 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -9,7 +9,7 @@
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/string_util.h" 10#include "common/string_util.h"
11#include "core/file_sys/archive_savedata.h" 11#include "core/file_sys/archive_savedata.h"
12#include "core/file_sys/disk_archive.h" 12#include "core/file_sys/savedata_archive.h"
13#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
14#include "core/hle/service/fs/archive.h" 14#include "core/hle/service/fs/archive.h"
15 15
@@ -54,7 +54,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const P
54 ErrorSummary::InvalidState, ErrorLevel::Status); 54 ErrorSummary::InvalidState, ErrorLevel::Status);
55 } 55 }
56 56
57 auto archive = std::make_unique<DiskArchive>(std::move(concrete_mount_point)); 57 auto archive = std::make_unique<SaveDataArchive>(std::move(concrete_mount_point));
58 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 58 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
59} 59}
60 60
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
index 48ebc0ed4..54e7793e0 100644
--- a/src/core/file_sys/archive_systemsavedata.cpp
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -9,7 +9,7 @@
9#include "common/file_util.h" 9#include "common/file_util.h"
10#include "common/string_util.h" 10#include "common/string_util.h"
11#include "core/file_sys/archive_systemsavedata.h" 11#include "core/file_sys/archive_systemsavedata.h"
12#include "core/file_sys/disk_archive.h" 12#include "core/file_sys/savedata_archive.h"
13#include "core/hle/service/fs/archive.h" 13#include "core/hle/service/fs/archive.h"
14 14
15//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -56,7 +56,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c
56 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, 56 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
57 ErrorSummary::InvalidState, ErrorLevel::Status); 57 ErrorSummary::InvalidState, ErrorLevel::Status);
58 } 58 }
59 auto archive = std::make_unique<DiskArchive>(fullpath); 59 auto archive = std::make_unique<SaveDataArchive>(fullpath);
60 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 60 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
61} 61}
62 62
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h
new file mode 100644
index 000000000..da7e82642
--- /dev/null
+++ b/src/core/file_sys/errors.h
@@ -0,0 +1,29 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/result.h"
6
7namespace FileSys {
8
9const ResultCode ERROR_INVALID_PATH(ErrorDescription::FS_InvalidPath, ErrorModule::FS,
10 ErrorSummary::InvalidArgument, ErrorLevel::Usage);
11const ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ErrorDescription::FS_UnsupportedOpenFlags,
12 ErrorModule::FS, ErrorSummary::NotSupported,
13 ErrorLevel::Usage);
14const ResultCode ERROR_FILE_NOT_FOUND(ErrorDescription::FS_FileNotFound, ErrorModule::FS,
15 ErrorSummary::NotFound, ErrorLevel::Status);
16const ResultCode ERROR_PATH_NOT_FOUND(ErrorDescription::FS_PathNotFound, ErrorModule::FS,
17 ErrorSummary::NotFound, ErrorLevel::Status);
18const ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ErrorDescription::FS_UnexpectedFileOrDirectory,
19 ErrorModule::FS, ErrorSummary::NotSupported,
20 ErrorLevel::Usage);
21const ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ErrorDescription::FS_DirectoryAlreadyExists,
22 ErrorModule::FS, ErrorSummary::NothingHappened,
23 ErrorLevel::Status);
24const ResultCode ERROR_FILE_ALREADY_EXISTS(ErrorDescription::FS_FileAlreadyExists, ErrorModule::FS,
25 ErrorSummary::NothingHappened, ErrorLevel::Status);
26const ResultCode ERROR_DIRECTORY_NOT_EMPTY(ErrorDescription::FS_DirectoryNotEmpty, ErrorModule::FS,
27 ErrorSummary::Canceled, ErrorLevel::Status);
28
29} // namespace FileSys
diff --git a/src/core/file_sys/savedata_archive.cpp b/src/core/file_sys/savedata_archive.cpp
new file mode 100644
index 000000000..f2e6a06bc
--- /dev/null
+++ b/src/core/file_sys/savedata_archive.cpp
@@ -0,0 +1,283 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/file_util.h"
6#include "core/file_sys/disk_archive.h"
7#include "core/file_sys/errors.h"
8#include "core/file_sys/path_parser.h"
9#include "core/file_sys/savedata_archive.h"
10
11////////////////////////////////////////////////////////////////////////////////////////////////////
12// FileSys namespace
13
14namespace FileSys {
15
16ResultVal<std::unique_ptr<FileBackend>> SaveDataArchive::OpenFile(const Path& path,
17 const Mode& mode) const {
18 LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
19
20 const PathParser path_parser(path);
21
22 if (!path_parser.IsValid()) {
23 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
24 return ERROR_INVALID_PATH;
25 }
26
27 if (mode.hex == 0) {
28 LOG_ERROR(Service_FS, "Empty open mode");
29 return ERROR_UNSUPPORTED_OPEN_FLAGS;
30 }
31
32 if (mode.create_flag && !mode.write_flag) {
33 LOG_ERROR(Service_FS, "Create flag set but write flag not set");
34 return ERROR_UNSUPPORTED_OPEN_FLAGS;
35 }
36
37 const auto full_path = path_parser.BuildHostPath(mount_point);
38
39 switch (path_parser.GetHostStatus(mount_point)) {
40 case PathParser::InvalidMountPoint:
41 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
42 return ERROR_FILE_NOT_FOUND;
43 case PathParser::PathNotFound:
44 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
45 return ERROR_PATH_NOT_FOUND;
46 case PathParser::FileInPath:
47 case PathParser::DirectoryFound:
48 LOG_ERROR(Service_FS, "Unexpected file or directory in %s", full_path.c_str());
49 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
50 case PathParser::NotFound:
51 if (!mode.create_flag) {
52 LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.",
53 full_path.c_str());
54 return ERROR_FILE_NOT_FOUND;
55 } else {
56 // Create the file
57 FileUtil::CreateEmptyFile(full_path);
58 }
59 break;
60 }
61
62 FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
63 if (!file.IsOpen()) {
64 LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening %s", full_path.c_str());
65 return ERROR_FILE_NOT_FOUND;
66 }
67
68 auto disk_file = std::make_unique<DiskFile>(std::move(file), mode);
69 return MakeResult<std::unique_ptr<FileBackend>>(std::move(disk_file));
70}
71
72ResultCode SaveDataArchive::DeleteFile(const Path& path) const {
73 const PathParser path_parser(path);
74
75 if (!path_parser.IsValid()) {
76 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
77 return ERROR_INVALID_PATH;
78 }
79
80 const auto full_path = path_parser.BuildHostPath(mount_point);
81
82 switch (path_parser.GetHostStatus(mount_point)) {
83 case PathParser::InvalidMountPoint:
84 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
85 return ERROR_FILE_NOT_FOUND;
86 case PathParser::PathNotFound:
87 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
88 return ERROR_PATH_NOT_FOUND;
89 case PathParser::FileInPath:
90 case PathParser::DirectoryFound:
91 case PathParser::NotFound:
92 LOG_ERROR(Service_FS, "File not found %s", full_path.c_str());
93 return ERROR_FILE_NOT_FOUND;
94 }
95
96 if (FileUtil::Delete(full_path)) {
97 return RESULT_SUCCESS;
98 }
99
100 LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting %s", full_path.c_str());
101 return ERROR_FILE_NOT_FOUND;
102}
103
104ResultCode SaveDataArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
105 if (FileUtil::Rename(mount_point + src_path.AsString(), mount_point + dest_path.AsString())) {
106 return RESULT_SUCCESS;
107 }
108
109 // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
110 // exist or similar. Verify.
111 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
112 ErrorSummary::NothingHappened, ErrorLevel::Status);
113}
114
115template <typename T>
116static ResultCode DeleteDirectoryHelper(const Path& path, const std::string& mount_point,
117 T deleter) {
118 const PathParser path_parser(path);
119
120 if (!path_parser.IsValid()) {
121 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
122 return ERROR_INVALID_PATH;
123 }
124
125 if (path_parser.IsRootDirectory())
126 return ERROR_DIRECTORY_NOT_EMPTY;
127
128 const auto full_path = path_parser.BuildHostPath(mount_point);
129
130 switch (path_parser.GetHostStatus(mount_point)) {
131 case PathParser::InvalidMountPoint:
132 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
133 return ERROR_PATH_NOT_FOUND;
134 case PathParser::PathNotFound:
135 case PathParser::NotFound:
136 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
137 return ERROR_PATH_NOT_FOUND;
138 case PathParser::FileInPath:
139 case PathParser::FileFound:
140 LOG_ERROR(Service_FS, "Unexpected file or directory %s", full_path.c_str());
141 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
142 }
143
144 if (deleter(full_path)) {
145 return RESULT_SUCCESS;
146 }
147
148 LOG_ERROR(Service_FS, "Directory not empty %s", full_path.c_str());
149 return ERROR_DIRECTORY_NOT_EMPTY;
150}
151
152ResultCode SaveDataArchive::DeleteDirectory(const Path& path) const {
153 return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir);
154}
155
156ResultCode SaveDataArchive::DeleteDirectoryRecursively(const Path& path) const {
157 return DeleteDirectoryHelper(
158 path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); });
159}
160
161ResultCode SaveDataArchive::CreateFile(const FileSys::Path& path, u64 size) const {
162 const PathParser path_parser(path);
163
164 if (!path_parser.IsValid()) {
165 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
166 return ERROR_INVALID_PATH;
167 }
168
169 const auto full_path = path_parser.BuildHostPath(mount_point);
170
171 switch (path_parser.GetHostStatus(mount_point)) {
172 case PathParser::InvalidMountPoint:
173 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
174 return ERROR_FILE_NOT_FOUND;
175 case PathParser::PathNotFound:
176 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
177 return ERROR_PATH_NOT_FOUND;
178 case PathParser::FileInPath:
179 LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str());
180 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
181 case PathParser::DirectoryFound:
182 case PathParser::FileFound:
183 LOG_ERROR(Service_FS, "%s already exists", full_path.c_str());
184 return ERROR_FILE_ALREADY_EXISTS;
185 }
186
187 if (size == 0) {
188 FileUtil::CreateEmptyFile(full_path);
189 return RESULT_SUCCESS;
190 }
191
192 FileUtil::IOFile file(full_path, "wb");
193 // Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
194 // We do this by seeking to the right size, then writing a single null byte.
195 if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) {
196 return RESULT_SUCCESS;
197 }
198
199 LOG_ERROR(Service_FS, "Too large file");
200 return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource,
201 ErrorLevel::Info);
202}
203
204ResultCode SaveDataArchive::CreateDirectory(const Path& path) const {
205 const PathParser path_parser(path);
206
207 if (!path_parser.IsValid()) {
208 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
209 return ERROR_INVALID_PATH;
210 }
211
212 const auto full_path = path_parser.BuildHostPath(mount_point);
213
214 switch (path_parser.GetHostStatus(mount_point)) {
215 case PathParser::InvalidMountPoint:
216 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
217 return ERROR_FILE_NOT_FOUND;
218 case PathParser::PathNotFound:
219 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
220 return ERROR_PATH_NOT_FOUND;
221 case PathParser::FileInPath:
222 LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str());
223 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
224 case PathParser::DirectoryFound:
225 case PathParser::FileFound:
226 LOG_ERROR(Service_FS, "%s already exists", full_path.c_str());
227 return ERROR_DIRECTORY_ALREADY_EXISTS;
228 }
229
230 if (FileUtil::CreateDir(mount_point + path.AsString())) {
231 return RESULT_SUCCESS;
232 }
233
234 LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", mount_point.c_str());
235 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled,
236 ErrorLevel::Status);
237}
238
239ResultCode SaveDataArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
240 if (FileUtil::Rename(mount_point + src_path.AsString(), mount_point + dest_path.AsString()))
241 return RESULT_SUCCESS;
242
243 // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
244 // exist or similar. Verify.
245 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
246 ErrorSummary::NothingHappened, ErrorLevel::Status);
247}
248
249ResultVal<std::unique_ptr<DirectoryBackend>> SaveDataArchive::OpenDirectory(
250 const Path& path) const {
251 const PathParser path_parser(path);
252
253 if (!path_parser.IsValid()) {
254 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
255 return ERROR_INVALID_PATH;
256 }
257
258 const auto full_path = path_parser.BuildHostPath(mount_point);
259
260 switch (path_parser.GetHostStatus(mount_point)) {
261 case PathParser::InvalidMountPoint:
262 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
263 return ERROR_FILE_NOT_FOUND;
264 case PathParser::PathNotFound:
265 case PathParser::NotFound:
266 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
267 return ERROR_PATH_NOT_FOUND;
268 case PathParser::FileInPath:
269 case PathParser::FileFound:
270 LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str());
271 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
272 }
273
274 auto directory = std::make_unique<DiskDirectory>(full_path);
275 return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory));
276}
277
278u64 SaveDataArchive::GetFreeBytes() const {
279 // TODO: Stubbed to return 1GiB
280 return 1024 * 1024 * 1024;
281}
282
283} // namespace FileSys
diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h
new file mode 100644
index 000000000..2fb6c452a
--- /dev/null
+++ b/src/core/file_sys/savedata_archive.h
@@ -0,0 +1,43 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <string>
8#include "core/file_sys/archive_backend.h"
9#include "core/file_sys/directory_backend.h"
10#include "core/file_sys/file_backend.h"
11#include "core/hle/result.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18/// Archive backend for general save data archive type (SaveData and SystemSaveData)
19class SaveDataArchive : public ArchiveBackend {
20public:
21 SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
22
23 std::string GetName() const override {
24 return "SaveDataArchive: " + mount_point;
25 }
26
27 ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
28 const Mode& mode) const override;
29 ResultCode DeleteFile(const Path& path) const override;
30 ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override;
31 ResultCode DeleteDirectory(const Path& path) const override;
32 ResultCode DeleteDirectoryRecursively(const Path& path) const override;
33 ResultCode CreateFile(const Path& path, u64 size) const override;
34 ResultCode CreateDirectory(const Path& path) const override;
35 ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
36 ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
37 u64 GetFreeBytes() const override;
38
39protected:
40 std::string mount_point;
41};
42
43} // namespace FileSys
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 7f8d8e00d..8330894f2 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -20,15 +20,22 @@ enum class ErrorDescription : u32 {
20 OS_InvalidBufferDescriptor = 48, 20 OS_InvalidBufferDescriptor = 48,
21 WrongAddress = 53, 21 WrongAddress = 53,
22 FS_ArchiveNotMounted = 101, 22 FS_ArchiveNotMounted = 101,
23 FS_FileNotFound = 112,
24 FS_PathNotFound = 113,
23 FS_NotFound = 120, 25 FS_NotFound = 120,
26 FS_FileAlreadyExists = 180,
27 FS_DirectoryAlreadyExists = 185,
24 FS_AlreadyExists = 190, 28 FS_AlreadyExists = 190,
25 FS_InvalidOpenFlags = 230, 29 FS_InvalidOpenFlags = 230,
30 FS_DirectoryNotEmpty = 240,
26 FS_NotAFile = 250, 31 FS_NotAFile = 250,
27 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive 32 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
28 OutofRangeOrMisalignedAddress = 33 OutofRangeOrMisalignedAddress =
29 513, // TODO(purpasmart): Check if this name fits its actual usage 34 513, // TODO(purpasmart): Check if this name fits its actual usage
30 GPU_FirstInitialization = 519, 35 GPU_FirstInitialization = 519,
31 FS_InvalidPath = 702, 36 FS_InvalidPath = 702,
37 FS_UnsupportedOpenFlags = 760,
38 FS_UnexpectedFileOrDirectory = 770,
32 InvalidSection = 1000, 39 InvalidSection = 1000,
33 TooLarge = 1001, 40 TooLarge = 1001,
34 NotAuthorized = 1002, 41 NotAuthorized = 1002,