Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
d775f13a
Commit
d775f13a
authored
Sep 04, 2016
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fs/io/FileOutputStream: merge all classes into one, add enum Mode
Prepare to add more modes.
parent
b630afde
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
118 additions
and
136 deletions
+118
-136
PlaylistFile.cxx
src/PlaylistFile.cxx
+1
-2
FileOutputStream.cxx
src/fs/io/FileOutputStream.cxx
+72
-63
FileOutputStream.hxx
src/fs/io/FileOutputStream.hxx
+45
-71
No files found.
src/PlaylistFile.cxx
View file @
d775f13a
...
...
@@ -199,7 +199,6 @@ SavePlaylistFile(const PlaylistFileContents &contents, const char *utf8path)
assert
(
!
path_fs
.
IsNull
());
FileOutputStream
fos
(
path_fs
);
BufferedOutputStream
bos
(
fos
);
for
(
const
auto
&
uri_utf8
:
contents
)
...
...
@@ -354,7 +353,7 @@ try {
const
auto
path_fs
=
spl_map_to_fs
(
utf8path
);
assert
(
!
path_fs
.
IsNull
());
AppendFileOutputStream
fos
(
path_fs
);
FileOutputStream
fos
(
path_fs
,
FileOutputStream
::
Mode
::
APPEND_EXISTING
);
if
(
fos
.
Tell
()
/
(
MPD_PATH_MAX
+
1
)
>=
playlist_max_length
)
throw
PlaylistError
(
PlaylistResult
::
TOO_LARGE
,
...
...
src/fs/io/FileOutputStream.cxx
View file @
d775f13a
...
...
@@ -21,22 +21,56 @@
#include "FileOutputStream.hxx"
#include "system/Error.hxx"
FileOutputStream
::
FileOutputStream
(
Path
_path
,
Mode
_mode
)
:
path
(
_path
),
mode
(
_mode
)
{
switch
(
mode
)
{
case
Mode
:
:
CREATE
:
OpenCreate
();
break
;
case
Mode
:
:
APPEND_EXISTING
:
OpenAppendExisting
();
break
;
}
}
#ifdef WIN32
FileOutputStream
::
FileOutputStream
(
Path
_path
)
:
BaseFileOutputStream
(
_path
)
inline
void
FileOutputStream
::
OpenCreate
(
)
{
SetHandle
(
CreateFile
(
_
path
.
c_str
(),
GENERIC_WRITE
,
0
,
nullptr
,
CREATE_ALWAYS
,
FILE_ATTRIBUTE_NORMAL
|
FILE_FLAG_WRITE_THROUGH
,
nullptr
)
);
handle
=
CreateFile
(
path
.
c_str
(),
GENERIC_WRITE
,
0
,
nullptr
,
CREATE_ALWAYS
,
FILE_ATTRIBUTE_NORMAL
|
FILE_FLAG_WRITE_THROUGH
,
nullptr
);
if
(
!
IsDefined
())
throw
FormatLastError
(
"Failed to create %s"
,
GetPath
().
ToUTF8
().
c_str
());
path
.
ToUTF8
().
c_str
());
}
inline
void
FileOutputStream
::
OpenAppendExisting
()
{
handle
=
CreateFile
(
path
.
c_str
(),
GENERIC_WRITE
,
0
,
nullptr
,
OPEN_EXISTING
,
FILE_ATTRIBUTE_NORMAL
|
FILE_FLAG_WRITE_THROUGH
,
nullptr
);
if
(
!
IsDefined
())
throw
FormatLastError
(
"Failed to append to %s"
,
path
.
ToUTF8
().
c_str
());
if
(
!
SeekEOF
())
{
auto
code
=
GetLastError
();
Close
();
throw
FormatLastError
(
code
,
"Failed seek end-of-file of %s"
,
path
.
ToUTF8
().
c_str
());
}
}
uint64_t
Base
FileOutputStream
::
Tell
()
const
FileOutputStream
::
Tell
()
const
{
LONG
high
=
0
;
DWORD
low
=
SetFilePointer
(
handle
,
0
,
&
high
,
FILE_CURRENT
);
...
...
@@ -47,7 +81,7 @@ BaseFileOutputStream::Tell() const
}
void
Base
FileOutputStream
::
Write
(
const
void
*
data
,
size_t
size
)
FileOutputStream
::
Write
(
const
void
*
data
,
size_t
size
)
{
assert
(
IsDefined
());
...
...
@@ -108,18 +142,18 @@ OpenTempFile(FileDescriptor &fd, Path path)
#endif
/* HAVE_LINKAT */
FileOutputStream
::
FileOutputStream
(
Path
_path
)
:
BaseFileOutputStream
(
_path
)
inline
void
FileOutputStream
::
OpenCreate
(
)
{
#ifdef HAVE_LINKAT
/* try Linux's O_TMPFILE first */
is_tmpfile
=
OpenTempFile
(
SetFD
()
,
GetPath
());
is_tmpfile
=
OpenTempFile
(
fd
,
GetPath
());
if
(
!
is_tmpfile
)
{
#endif
/* fall back to plain POSIX */
if
(
!
SetFD
()
.
Open
(
GetPath
().
c_str
(),
O_WRONLY
|
O_CREAT
|
O_TRUNC
,
0666
))
if
(
!
fd
.
Open
(
GetPath
().
c_str
(),
O_WRONLY
|
O_CREAT
|
O_TRUNC
,
0666
))
throw
FormatErrno
(
"Failed to create %s"
,
GetPath
().
c_str
());
#ifdef HAVE_LINKAT
...
...
@@ -127,14 +161,22 @@ FileOutputStream::FileOutputStream(Path _path)
#endif
}
inline
void
FileOutputStream
::
OpenAppendExisting
()
{
if
(
!
fd
.
Open
(
path
.
c_str
(),
O_WRONLY
|
O_APPEND
))
throw
FormatErrno
(
"Failed to append to %s"
,
path
.
c_str
());
}
uint64_t
Base
FileOutputStream
::
Tell
()
const
FileOutputStream
::
Tell
()
const
{
return
fd
.
Tell
();
}
void
Base
FileOutputStream
::
Write
(
const
void
*
data
,
size_t
size
)
FileOutputStream
::
Write
(
const
void
*
data
,
size_t
size
)
{
assert
(
IsDefined
());
...
...
@@ -158,20 +200,20 @@ FileOutputStream::Commit()
/* hard-link the temporary file to the final path */
char
fd_path
[
64
];
snprintf
(
fd_path
,
sizeof
(
fd_path
),
"/proc/self/fd/%d"
,
GetFD
()
.
Get
());
if
(
linkat
(
AT_FDCWD
,
fd_path
,
AT_FDCWD
,
GetPath
()
.
c_str
(),
fd
.
Get
());
if
(
linkat
(
AT_FDCWD
,
fd_path
,
AT_FDCWD
,
path
.
c_str
(),
AT_SYMLINK_FOLLOW
)
<
0
)
throw
FormatErrno
(
"Failed to commit %s"
,
GetPath
()
.
c_str
());
path
.
c_str
());
}
#endif
if
(
!
Close
())
{
#ifdef WIN32
throw
FormatLastError
(
"Failed to commit %s"
,
GetPath
()
.
ToUTF8
().
c_str
());
path
.
ToUTF8
().
c_str
());
#else
throw
FormatErrno
(
"Failed to commit %s"
,
GetPath
()
.
c_str
());
throw
FormatErrno
(
"Failed to commit %s"
,
path
.
c_str
());
#endif
}
}
...
...
@@ -183,51 +225,18 @@ FileOutputStream::Cancel()
Close
();
switch
(
mode
)
{
case
Mode
:
:
CREATE
:
#ifdef HAVE_LINKAT
if
(
!
is_tmpfile
)
#endif
unlink
(
GetPath
().
c_str
());
}
if
(
!
is_tmpfile
)
#endif
unlink
(
GetPath
().
c_str
());
break
;
AppendFileOutputStream
::
AppendFileOutputStream
(
Path
_path
)
:
BaseFileOutputStream
(
_path
)
{
#ifdef WIN32
SetHandle
(
CreateFile
(
GetPath
().
c_str
(),
GENERIC_WRITE
,
0
,
nullptr
,
OPEN_EXISTING
,
FILE_ATTRIBUTE_NORMAL
|
FILE_FLAG_WRITE_THROUGH
,
nullptr
));
if
(
!
IsDefined
())
throw
FormatLastError
(
"Failed to append to %s"
,
GetPath
().
ToUTF8
().
c_str
());
if
(
!
SeekEOF
())
{
auto
code
=
GetLastError
();
Close
();
throw
FormatLastError
(
code
,
"Failed seek end-of-file of %s"
,
GetPath
().
ToUTF8
().
c_str
());
case
Mode
:
:
APPEND_EXISTING
:
/* can't roll this back */
break
;
}
#else
if
(
!
SetFD
().
Open
(
GetPath
().
c_str
(),
O_WRONLY
|
O_APPEND
))
throw
FormatErrno
(
"Failed to append to %s"
,
GetPath
().
c_str
());
#endif
}
void
AppendFileOutputStream
::
Commit
()
{
assert
(
IsDefined
());
if
(
!
Close
())
{
#ifdef WIN32
throw
FormatLastError
(
"Failed to commit %s"
,
GetPath
().
ToUTF8
().
c_str
());
#else
throw
FormatErrno
(
"Failed to commit %s"
,
GetPath
().
c_str
());
#endif
}
}
src/fs/io/FileOutputStream.hxx
View file @
d775f13a
...
...
@@ -38,7 +38,7 @@
class
Path
;
class
BaseFileOutputStream
:
public
OutputStream
{
class
FileOutputStream
final
:
public
OutputStream
{
const
AllocatedPath
path
;
#ifdef WIN32
...
...
@@ -47,40 +47,58 @@ class BaseFileOutputStream : public OutputStream {
FileDescriptor
fd
=
FileDescriptor
::
Undefined
();
#endif
protected
:
#ifdef WIN32
template
<
typename
P
>
BaseFileOutputStream
(
P
&&
_path
)
:
path
(
std
::
forward
<
P
>
(
_path
))
{}
#else
template
<
typename
P
>
BaseFileOutputStream
(
P
&&
_path
)
:
path
(
std
::
forward
<
P
>
(
_path
))
{}
#ifdef HAVE_LINKAT
/**
* Was O_TMPFILE used? If yes, then linkat() must be used to
* create a link to this file.
*/
bool
is_tmpfile
=
false
;
#endif
~
BaseFileOutputStream
()
{
assert
(
!
IsDefined
());
}
#ifdef WIN32
void
SetHandle
(
HANDLE
_handle
)
{
assert
(
!
IsDefined
());
public
:
enum
class
Mode
:
uint8_t
{
/**
* Create a new file, or replace an existing file.
* File contents may not be visible until Commit() has
* been called.
*/
CREATE
,
/**
* Append to a file that already exists. If it does
* not, an exception is thrown.
*/
APPEND_EXISTING
,
};
private
:
Mode
mode
;
handle
=
_handle
;
public
:
FileOutputStream
(
Path
_path
,
Mode
_mode
=
Mode
::
CREATE
);
assert
(
IsDefined
());
~
FileOutputStream
()
{
if
(
IsDefined
())
Cancel
();
}
#else
FileDescriptor
&
SetFD
()
{
assert
(
!
IsDefined
());
return
fd
;
public
:
Path
GetPath
()
const
{
return
path
;
}
const
FileDescriptor
&
GetFD
()
const
{
return
fd
;
}
#endif
gcc_pure
uint64_t
Tell
()
const
;
/* virtual methods from class OutputStream */
void
Write
(
const
void
*
data
,
size_t
size
)
override
;
void
Commit
();
void
Cancel
();
private
:
void
OpenCreate
();
void
OpenAppendExisting
();
bool
Close
()
{
assert
(
IsDefined
());
...
...
@@ -108,50 +126,6 @@ protected:
return
fd
.
IsDefined
();
#endif
}
public
:
Path
GetPath
()
const
{
return
path
;
}
gcc_pure
uint64_t
Tell
()
const
;
/* virtual methods from class OutputStream */
void
Write
(
const
void
*
data
,
size_t
size
)
override
;
};
class
FileOutputStream
final
:
public
BaseFileOutputStream
{
#ifdef HAVE_LINKAT
/**
* Was O_TMPFILE used? If yes, then linkat() must be used to
* create a link to this file.
*/
bool
is_tmpfile
;
#endif
public
:
FileOutputStream
(
Path
_path
);
~
FileOutputStream
()
{
if
(
IsDefined
())
Cancel
();
}
void
Commit
();
void
Cancel
();
};
class
AppendFileOutputStream
final
:
public
BaseFileOutputStream
{
public
:
AppendFileOutputStream
(
Path
_path
);
~
AppendFileOutputStream
()
{
if
(
IsDefined
())
Close
();
}
void
Commit
();
};
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment