Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
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
wine
wine-winehq
Commits
d603b22a
Commit
d603b22a
authored
Sep 16, 2021
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
shell32: Load the XDG user dirs config file using Win32 APIs.
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
39ca4de6
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
113 additions
and
311 deletions
+113
-311
shellpath.c
dlls/shell32/shellpath.c
+113
-80
xdg.c
dlls/shell32/xdg.c
+0
-229
xdg.h
dlls/shell32/xdg.h
+0
-2
No files found.
dlls/shell32/shellpath.c
View file @
d603b22a
...
...
@@ -49,7 +49,6 @@
#include "pidl.h"
#include "wine/unicode.h"
#include "shlwapi.h"
#include "xdg.h"
#include "sddl.h"
#include "knownfolders.h"
#include "initguid.h"
...
...
@@ -4042,52 +4041,111 @@ end:
return
hr
;
}
/*************************************************************************
* _SHGetXDGUserDirs [Internal]
*
* Get XDG directories paths from XDG configuration.
*
* PARAMS
* xdg_dirs [I] Array of XDG directories to look for.
* num_dirs [I] Number of elements in xdg_dirs.
* xdg_results [O] An array of the XDG directories paths.
*/
static
inline
void
_SHGetXDGUserDirs
(
const
char
*
const
*
xdg_dirs
,
const
unsigned
int
num_dirs
,
char
***
xdg_results
)
{
HRESULT
hr
;
static
char
*
xdg_config
;
static
DWORD
xdg_config_len
;
hr
=
XDG_UserDirLookup
(
xdg_dirs
,
num_dirs
,
xdg_results
);
if
(
FAILED
(
hr
))
*
xdg_results
=
NULL
;
static
BOOL
WINAPI
init_xdg_dirs
(
INIT_ONCE
*
once
,
void
*
param
,
void
**
context
)
{
static
const
WCHAR
configW
[]
=
{
'X'
,
'D'
,
'G'
,
'_'
,
'C'
,
'O'
,
'N'
,
'F'
,
'I'
,
'G'
,
'_'
,
'H'
,
'O'
,
'M'
,
'E'
,
0
};
static
const
WCHAR
homedirW
[]
=
{
'W'
,
'I'
,
'N'
,
'E'
,
'H'
,
'O'
,
'M'
,
'E'
,
'D'
,
'I'
,
'R'
,
0
};
static
const
WCHAR
home_fmtW
[]
=
{
'%'
,
's'
,
'/'
,
'.'
,
'c'
,
'o'
,
'n'
,
'f'
,
'i'
,
'g'
,
'/'
,
'u'
,
's'
,
'e'
,
'r'
,
'-'
,
'd'
,
'i'
,
'r'
,
's'
,
'.'
,
'd'
,
'i'
,
'r'
,
's'
,
0
};
static
const
WCHAR
config_fmtW
[]
=
{
'\\'
,
'?'
,
'?'
,
'\\'
,
'u'
,
'n'
,
'i'
,
'x'
,
'%'
,
's'
,
'/'
,
'u'
,
's'
,
'e'
,
'r'
,
'-'
,
'd'
,
'i'
,
'r'
,
's'
,
'.'
,
'd'
,
'i'
,
'r'
,
's'
,
0
};
const
WCHAR
*
fmt
=
config_fmtW
;
char
*
p
;
WCHAR
*
name
,
*
ptr
;
HANDLE
file
;
DWORD
len
;
WCHAR
var
[
MAX_PATH
];
if
(
!
GetEnvironmentVariableW
(
configW
,
var
,
MAX_PATH
)
||
!
var
[
0
])
{
if
(
!
GetEnvironmentVariableW
(
homedirW
,
var
,
MAX_PATH
))
return
TRUE
;
fmt
=
home_fmtW
;
}
name
=
heap_alloc
(
(
strlenW
(
var
)
+
strlenW
(
fmt
))
*
sizeof
(
WCHAR
)
);
sprintfW
(
name
,
fmt
,
var
);
name
[
1
]
=
'\\'
;
/* change \??\ to \\?\ */
for
(
ptr
=
name
;
*
ptr
;
ptr
++
)
if
(
*
ptr
==
'/'
)
*
ptr
=
'\\'
;
file
=
CreateFileW
(
name
,
GENERIC_READ
,
FILE_SHARE_READ
,
NULL
,
OPEN_EXISTING
,
0
,
0
);
heap_free
(
name
);
if
(
file
!=
INVALID_HANDLE_VALUE
)
{
len
=
GetFileSize
(
file
,
NULL
);
if
(
!
(
xdg_config
=
heap_alloc
(
len
+
1
)))
return
TRUE
;
if
(
!
ReadFile
(
file
,
xdg_config
,
len
,
&
xdg_config_len
,
NULL
))
{
heap_free
(
xdg_config
);
xdg_config
=
NULL
;
}
else
{
for
(
p
=
xdg_config
;
p
<
xdg_config
+
xdg_config_len
;
p
++
)
if
(
*
p
==
'\n'
)
*
p
=
0
;
*
p
=
0
;
/* append null to simplify string parsing */
}
CloseHandle
(
file
);
}
return
TRUE
;
}
/*************************************************************************
* _SHFreeXDGUserDirs [Internal]
*
* Free resources allocated by XDG_UserDirLookup().
*
* PARAMS
* num_dirs [I] Number of elements in xdg_results.
* xdg_results [I] An array of the XDG directories paths.
*/
static
inline
void
_SHFreeXDGUserDirs
(
const
unsigned
int
num_dirs
,
char
**
xdg_results
)
{
UINT
i
;
static
char
*
get_xdg_path
(
const
char
*
var
)
{
static
INIT_ONCE
once
;
char
*
p
,
*
ret
=
NULL
;
int
i
;
InitOnceExecuteOnce
(
&
once
,
init_xdg_dirs
,
NULL
,
NULL
);
if
(
!
xdg_config
)
return
NULL
;
if
(
xdg_results
)
for
(
p
=
xdg_config
;
p
<
xdg_config
+
xdg_config_len
;
p
+=
strlen
(
p
)
+
1
)
{
for
(
i
=
0
;
i
<
num_dirs
;
i
++
)
heap_free
(
xdg_results
[
i
]);
heap_free
(
xdg_results
);
while
(
*
p
==
' '
||
*
p
==
'\t'
)
p
++
;
if
(
strncmp
(
p
,
var
,
strlen
(
var
)
))
continue
;
p
+=
strlen
(
var
);
while
(
*
p
==
' '
||
*
p
==
'\t'
)
p
++
;
if
(
*
p
!=
'='
)
continue
;
p
++
;
while
(
*
p
==
' '
||
*
p
==
'\t'
)
p
++
;
if
(
*
p
!=
'"'
)
continue
;
p
++
;
if
(
*
p
!=
'/'
&&
strncmp
(
p
,
"$HOME/"
,
6
))
continue
;
if
(
!
(
ret
=
heap_alloc
(
strlen
(
p
)
+
1
)))
break
;
for
(
i
=
0
;
*
p
&&
*
p
!=
'"'
;
i
++
,
p
++
)
{
if
(
*
p
==
'\\'
&&
p
[
1
])
p
++
;
ret
[
i
]
=
*
p
;
}
ret
[
i
]
=
0
;
if
(
*
p
!=
'"'
)
{
heap_free
(
ret
);
ret
=
NULL
;
}
break
;
}
return
ret
;
}
static
inline
void
build_path
(
char
*
dest
,
const
char
*
base
,
const
char
*
dir
)
static
BOOL
link_folder
(
const
char
*
target
,
const
char
*
link
)
{
int
len
;
struct
stat
st
;
char
*
dir
=
NULL
;
BOOL
ret
;
if
(
!
strcmp
(
target
,
"$HOME"
)
||
!
strncmp
(
target
,
"$HOME/"
,
6
))
{
const
char
*
home
=
getenv
(
"HOME"
);
lstrcpynA
(
dest
,
base
,
FILENAME_MAX
);
len
=
strlen
(
dest
);
if
(
!
len
||
dest
[
len
-
1
]
!=
'/'
)
dest
[
len
++
]
=
'/'
;
lstrcpynA
(
dest
+
len
,
dir
,
FILENAME_MAX
-
len
);
target
+=
5
;
dir
=
heap_alloc
(
strlen
(
home
)
+
strlen
(
target
)
+
1
);
strcpy
(
dir
,
home
);
strcat
(
dir
,
target
);
target
=
dir
;
}
if
((
ret
=
!
stat
(
target
,
&
st
)
&&
S_ISDIR
(
st
.
st_mode
)))
symlink
(
target
,
link
);
heap_free
(
dir
);
return
ret
;
}
/******************************************************************************
...
...
@@ -4098,47 +4156,22 @@ static inline void build_path( char *dest, const char *base, const char *dir )
*/
static
void
create_link
(
const
WCHAR
*
path
,
const
char
*
xdg_name
,
const
char
*
default_name
)
{
char
szMyStuffTarget
[
FILENAME_MAX
],
*
pszMyStuff
;
struct
stat
statFolder
;
const
char
*
pszHome
;
char
**
xdg_results
;
_SHGetXDGUserDirs
(
&
xdg_name
,
1
,
&
xdg_results
);
char
*
target
,
*
link
;
pszHome
=
getenv
(
"HOME"
)
;
if
(
!
(
link
=
wine_get_unix_file_name
(
path
)))
return
;
while
(
1
)
if
((
target
=
get_xdg_path
(
xdg_name
))
)
{
pszMyStuff
=
wine_get_unix_file_name
(
path
);
if
(
!
pszMyStuff
)
break
;
while
(
1
)
{
/* Try the XDG_XXX_DIR folder */
if
(
xdg_results
&&
xdg_results
[
0
])
{
strcpy
(
szMyStuffTarget
,
xdg_results
[
0
]);
break
;
}
/* Or the OS X folder (these are never localized) */
if
(
pszHome
)
{
build_path
(
szMyStuffTarget
,
pszHome
,
default_name
);
if
(
!
stat
(
szMyStuffTarget
,
&
statFolder
)
&&
S_ISDIR
(
statFolder
.
st_mode
))
break
;
}
/* As a last resort point to $HOME. */
strcpy
(
szMyStuffTarget
,
pszHome
);
break
;
}
symlink
(
szMyStuffTarget
,
pszMyStuff
);
heap_free
(
pszMyStuff
);
break
;
if
(
link_folder
(
target
,
link
))
goto
done
;
}
if
(
link_folder
(
default_name
,
link
))
goto
done
;
/* fall back to HOME */
link_folder
(
"$HOME"
,
link
);
_SHFreeXDGUserDirs
(
1
,
xdg_results
);
done:
heap_free
(
target
);
heap_free
(
link
);
}
/******************************************************************************
...
...
@@ -4156,25 +4189,25 @@ static void _SHCreateSymbolicLink(int nFolder, const WCHAR *path)
switch
(
folder
)
{
case
CSIDL_PERSONAL
:
create_link
(
path
,
"
DOCUMENTS"
,
"
Documents"
);
create_link
(
path
,
"
XDG_DOCUMENTS_DIR"
,
"$HOME/
Documents"
);
break
;
case
CSIDL_DESKTOPDIRECTORY
:
create_link
(
path
,
"
DESKTOP"
,
"
Desktop"
);
create_link
(
path
,
"
XDG_DESKTOP_DIR"
,
"$HOME/
Desktop"
);
break
;
case
CSIDL_MYPICTURES
:
create_link
(
path
,
"
PICTURES"
,
"
Pictures"
);
create_link
(
path
,
"
XDG_PICTURES_DIR"
,
"$HOME/
Pictures"
);
break
;
case
CSIDL_MYVIDEO
:
create_link
(
path
,
"
VIDEOS"
,
"
Movies"
);
create_link
(
path
,
"
XDG_VIDEOS_DIR"
,
"$HOME/
Movies"
);
break
;
case
CSIDL_MYMUSIC
:
create_link
(
path
,
"
MUSIC"
,
"
Music"
);
create_link
(
path
,
"
XDG_MUSIC_DIR"
,
"$HOME/
Music"
);
break
;
case
CSIDL_DOWNLOADS
:
create_link
(
path
,
"
DOWNLOAD"
,
"
Downloads"
);
create_link
(
path
,
"
XDG_DOWNLOAD_DIR"
,
"$HOME/
Downloads"
);
break
;
case
CSIDL_TEMPLATES
:
create_link
(
path
,
"
TEMPLATES"
,
"
Templates"
);
create_link
(
path
,
"
XDG_TEMPLATES_DIR"
,
"$HOME/
Templates"
);
break
;
}
}
...
...
dlls/shell32/xdg.c
View file @
d603b22a
...
...
@@ -741,232 +741,3 @@ char *XDG_GetStringValue(XDG_PARSED_FILE *file, const char *group_name, const ch
return
NULL
;
}
/* Get the name of the xdg configuration file.
*
* [in] home_dir - $HOME
* [out] config_file - the name of the configuration file
*/
static
HRESULT
get_xdg_config_file
(
char
*
home_dir
,
char
**
config_file
)
{
char
*
config_home
;
config_home
=
getenv
(
"XDG_CONFIG_HOME"
);
if
(
!
config_home
||
!
config_home
[
0
])
{
*
config_file
=
heap_alloc
(
strlen
(
home_dir
)
+
strlen
(
"/.config/user-dirs.dirs"
)
+
1
);
if
(
!*
config_file
)
return
E_OUTOFMEMORY
;
strcpy
(
*
config_file
,
home_dir
);
strcat
(
*
config_file
,
"/.config/user-dirs.dirs"
);
}
else
{
*
config_file
=
heap_alloc
(
strlen
(
config_home
)
+
strlen
(
"/user-dirs.dirs"
)
+
1
);
if
(
!*
config_file
)
return
E_OUTOFMEMORY
;
strcpy
(
*
config_file
,
config_home
);
strcat
(
*
config_file
,
"/user-dirs.dirs"
);
}
return
S_OK
;
}
/* Parse the key in a line in the xdg-user-dir config file.
* i.e. XDG_PICTURES_DIR="$HOME/Pictures"
* ^ ^
*
* [in] xdg_dirs - array of xdg directories to look for
* [in] num_dirs - number of elements in xdg_dirs
* [in/out] p_ptr - pointer to where we are in the buffer
* Returns the index to xdg_dirs if we find the key, or -1 on error.
*/
static
int
parse_config1
(
const
char
*
const
*
xdg_dirs
,
const
unsigned
int
num_dirs
,
char
**
p_ptr
)
{
char
*
p
;
int
i
;
p
=
*
p_ptr
;
while
(
*
p
==
' '
||
*
p
==
'\t'
)
p
++
;
if
(
strncmp
(
p
,
"XDG_"
,
4
))
return
-
1
;
p
+=
4
;
for
(
i
=
0
;
i
<
num_dirs
;
i
++
)
{
if
(
!
strncmp
(
p
,
xdg_dirs
[
i
],
strlen
(
xdg_dirs
[
i
])))
{
p
+=
strlen
(
xdg_dirs
[
i
]);
break
;
}
}
if
(
i
==
num_dirs
)
return
-
1
;
if
(
strncmp
(
p
,
"_DIR"
,
4
))
return
-
1
;
p
+=
4
;
while
(
*
p
==
' '
||
*
p
==
'\t'
)
p
++
;
if
(
*
p
!=
'='
)
return
-
1
;
p
++
;
while
(
*
p
==
' '
||
*
p
==
'\t'
)
p
++
;
if
(
*
p
!=
'"'
)
return
-
1
;
p
++
;
*
p_ptr
=
p
;
return
i
;
}
/* Parse the value in a line in the xdg-user-dir config file.
* i.e. XDG_PICTURES_DIR="$HOME/Pictures"
* ^ ^
*
* [in] p - pointer to the buffer
* [in] home_dir - $HOME
* [out] out_ptr - the directory name
*/
static
HRESULT
parse_config2
(
char
*
p
,
const
char
*
home_dir
,
char
**
out_ptr
)
{
BOOL
relative
;
char
*
out
,
*
d
;
relative
=
FALSE
;
if
(
!
strncmp
(
p
,
"$HOME/"
,
6
))
{
p
+=
6
;
relative
=
TRUE
;
}
else
if
(
*
p
!=
'/'
)
return
E_FAIL
;
if
(
relative
)
{
out
=
heap_alloc
(
strlen
(
home_dir
)
+
strlen
(
p
)
+
2
);
if
(
!
out
)
return
E_OUTOFMEMORY
;
strcpy
(
out
,
home_dir
);
strcat
(
out
,
"/"
);
}
else
{
out
=
heap_alloc
(
strlen
(
p
)
+
1
);
if
(
!
out
)
return
E_OUTOFMEMORY
;
*
out
=
0
;
}
d
=
out
+
strlen
(
out
);
while
(
*
p
&&
*
p
!=
'"'
)
{
if
((
*
p
==
'\\'
)
&&
(
*
(
p
+
1
)
!=
0
))
p
++
;
*
d
++
=
*
p
++
;
}
*
d
=
0
;
*
out_ptr
=
out
;
return
S_OK
;
}
/* Parse part of a line in the xdg-user-dir config file.
* i.e. XDG_PICTURES_DIR="$HOME/Pictures"
* ^ ^
*
* The calling function is responsible for freeing all elements of out_ptr as
* well as out_ptr itself.
*
* [in] xdg_dirs - array of xdg directories to look for
* [in] num_dirs - number of elements in xdg_dirs
* [out] out_ptr - an array of the xdg directories names
*/
HRESULT
XDG_UserDirLookup
(
const
char
*
const
*
xdg_dirs
,
const
unsigned
int
num_dirs
,
char
***
out_ptr
)
{
FILE
*
file
;
char
**
out
;
char
*
home_dir
,
*
config_file
;
char
buffer
[
512
];
int
len
;
unsigned
int
i
;
HRESULT
hr
;
*
out_ptr
=
heap_alloc_zero
(
num_dirs
*
sizeof
(
char
*
));
out
=
*
out_ptr
;
if
(
!
out
)
return
E_OUTOFMEMORY
;
home_dir
=
getenv
(
"HOME"
);
if
(
!
home_dir
)
{
hr
=
E_FAIL
;
goto
xdg_user_dir_lookup_error
;
}
hr
=
get_xdg_config_file
(
home_dir
,
&
config_file
);
if
(
FAILED
(
hr
))
goto
xdg_user_dir_lookup_error
;
file
=
fopen
(
config_file
,
"r"
);
heap_free
(
config_file
);
if
(
!
file
)
{
hr
=
E_HANDLE
;
goto
xdg_user_dir_lookup_error
;
}
while
(
fgets
(
buffer
,
sizeof
(
buffer
),
file
))
{
int
idx
;
char
*
p
;
/* Remove newline at end */
len
=
strlen
(
buffer
);
if
(
len
>
0
&&
buffer
[
len
-
1
]
==
'\n'
)
buffer
[
len
-
1
]
=
0
;
/* Parse the key */
p
=
buffer
;
idx
=
parse_config1
(
xdg_dirs
,
num_dirs
,
&
p
);
if
(
idx
<
0
)
continue
;
if
(
out
[
idx
])
continue
;
/* Parse the value */
hr
=
parse_config2
(
p
,
home_dir
,
&
out
[
idx
]);
if
(
hr
==
E_OUTOFMEMORY
)
{
fclose
(
file
);
goto
xdg_user_dir_lookup_error
;
}
}
fclose
(
file
);
hr
=
S_OK
;
/* Remove entries for directories that do not exist */
for
(
i
=
0
;
i
<
num_dirs
;
i
++
)
{
struct
stat
statFolder
;
if
(
!
out
[
i
])
continue
;
if
(
!
stat
(
out
[
i
],
&
statFolder
)
&&
S_ISDIR
(
statFolder
.
st_mode
))
continue
;
heap_free
(
out
[
i
]);
out
[
i
]
=
NULL
;
}
xdg_user_dir_lookup_error:
if
(
FAILED
(
hr
))
{
for
(
i
=
0
;
i
<
num_dirs
;
i
++
)
heap_free
(
out
[
i
]);
heap_free
(
*
out_ptr
);
}
return
hr
;
}
dlls/shell32/xdg.h
View file @
d603b22a
...
...
@@ -44,6 +44,4 @@ HRESULT TRASH_EnumItems(const WCHAR *path, LPITEMIDLIST **pidls, int *count) DEC
HRESULT
TRASH_RestoreItem
(
LPCITEMIDLIST
pidl
)
DECLSPEC_HIDDEN
;
HRESULT
TRASH_EraseItem
(
LPCITEMIDLIST
pidl
)
DECLSPEC_HIDDEN
;
HRESULT
XDG_UserDirLookup
(
const
char
*
const
*
xdg_dirs
,
const
unsigned
int
num_dirs
,
char
***
out_ptr
)
DECLSPEC_HIDDEN
;
#endif
/* ndef __XDG_H__ */
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