Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
82af599b
Commit
82af599b
authored
5 years ago
by
Al Viro
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
readdir.c: get compat_filldir() more or less in sync with filldir()
Signed-off-by:
Al Viro
<
viro@zeniv.linux.org.uk
>
parent
391b7461
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
27 additions
and
24 deletions
+27
-24
fs/readdir.c
fs/readdir.c
+27
-24
No files found.
fs/readdir.c
View file @
82af599b
...
...
@@ -473,7 +473,7 @@ struct compat_linux_dirent {
struct
compat_getdents_callback
{
struct
dir_context
ctx
;
struct
compat_linux_dirent
__user
*
current_dir
;
struct
compat_linux_dirent
__user
*
previous
;
int
prev_reclen
;
int
count
;
int
error
;
};
...
...
@@ -481,13 +481,17 @@ struct compat_getdents_callback {
static
int
compat_filldir
(
struct
dir_context
*
ctx
,
const
char
*
name
,
int
namlen
,
loff_t
offset
,
u64
ino
,
unsigned
int
d_type
)
{
struct
compat_linux_dirent
__user
*
dirent
;
struct
compat_linux_dirent
__user
*
dirent
,
*
prev
;
struct
compat_getdents_callback
*
buf
=
container_of
(
ctx
,
struct
compat_getdents_callback
,
ctx
);
compat_ulong_t
d_ino
;
int
reclen
=
ALIGN
(
offsetof
(
struct
compat_linux_dirent
,
d_name
)
+
namlen
+
2
,
sizeof
(
compat_long_t
));
int
prev_reclen
;
buf
->
error
=
verify_dirent_name
(
name
,
namlen
);
if
(
unlikely
(
buf
->
error
))
return
buf
->
error
;
buf
->
error
=
-
EINVAL
;
/* only used if we fail.. */
if
(
reclen
>
buf
->
count
)
return
-
EINVAL
;
...
...
@@ -496,29 +500,27 @@ static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
buf
->
error
=
-
EOVERFLOW
;
return
-
EOVERFLOW
;
}
dirent
=
buf
->
previous
;
if
(
dirent
)
{
if
(
signal_pending
(
current
))
prev_reclen
=
buf
->
prev_reclen
;
if
(
prev_reclen
&&
signal_pending
(
current
))
return
-
EINTR
;
if
(
__put_user
(
offset
,
&
dirent
->
d_off
))
goto
efault
;
}
dirent
=
buf
->
current_dir
;
if
(
__put_user
(
d_ino
,
&
dirent
->
d_ino
))
goto
efault
;
if
(
__put_user
(
reclen
,
&
dirent
->
d_reclen
))
goto
efault
;
if
(
copy_to_user
(
dirent
->
d_name
,
name
,
namlen
))
goto
efault
;
if
(
__put_user
(
0
,
dirent
->
d_name
+
namlen
))
goto
efault
;
if
(
__put_user
(
d_type
,
(
char
__user
*
)
dirent
+
reclen
-
1
))
prev
=
(
void
__user
*
)
dirent
-
prev_reclen
;
if
(
!
user_write_access_begin
(
prev
,
reclen
+
prev_reclen
))
goto
efault
;
buf
->
previous
=
dirent
;
dirent
=
(
void
__user
*
)
dirent
+
reclen
;
buf
->
current_dir
=
dirent
;
unsafe_put_user
(
offset
,
&
prev
->
d_off
,
efault_end
);
unsafe_put_user
(
d_ino
,
&
dirent
->
d_ino
,
efault_end
);
unsafe_put_user
(
reclen
,
&
dirent
->
d_reclen
,
efault_end
);
unsafe_put_user
(
d_type
,
(
char
__user
*
)
dirent
+
reclen
-
1
,
efault_end
);
unsafe_copy_dirent_name
(
dirent
->
d_name
,
name
,
namlen
,
efault_end
);
user_write_access_end
();
buf
->
prev_reclen
=
reclen
;
buf
->
current_dir
=
(
void
__user
*
)
dirent
+
reclen
;
buf
->
count
-=
reclen
;
return
0
;
efault_end:
user_write_access_end
();
efault:
buf
->
error
=
-
EFAULT
;
return
-
EFAULT
;
...
...
@@ -528,7 +530,6 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
struct
compat_linux_dirent
__user
*
,
dirent
,
unsigned
int
,
count
)
{
struct
fd
f
;
struct
compat_linux_dirent
__user
*
lastdirent
;
struct
compat_getdents_callback
buf
=
{
.
ctx
.
actor
=
compat_filldir
,
.
current_dir
=
dirent
,
...
...
@@ -546,8 +547,10 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
error
=
iterate_dir
(
f
.
file
,
&
buf
.
ctx
);
if
(
error
>=
0
)
error
=
buf
.
error
;
lastdirent
=
buf
.
previous
;
if
(
lastdirent
)
{
if
(
buf
.
prev_reclen
)
{
struct
compat_linux_dirent
__user
*
lastdirent
;
lastdirent
=
(
void
__user
*
)
buf
.
current_dir
-
buf
.
prev_reclen
;
if
(
put_user
(
buf
.
ctx
.
pos
,
&
lastdirent
->
d_off
))
error
=
-
EFAULT
;
else
...
...
This diff is collapsed.
Click to expand it.
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