Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: "Martin Storsjö" <martin@martin.st>
To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Cc: softworkz <softworkz@hotmail.com>, Hendrik Leppkes <h.leppkes@gmail.com>
Subject: Re: [FFmpeg-devel] [PATCH v5 1/2] avutil/wchar_filename, file_open: Support long file names on Windows
Date: Tue, 24 May 2022 12:09:51 +0300 (EEST)
Message-ID: <67674be9-ee2-9918-b3e5-3183633e9ba@martin.st> (raw)
In-Reply-To: <13118dc1faccb2e31f92dd21511b6558a6e9ab3d.1653381808.git.ffmpegagent@gmail.com>

On Tue, 24 May 2022, softworkz wrote:

> From: softworkz <softworkz@hotmail.com>
>
> Signed-off-by: softworkz <softworkz@hotmail.com>
> ---
> libavutil/file_open.c      |   2 +-
> libavutil/wchar_filename.h | 166 +++++++++++++++++++++++++++++++++++++
> 2 files changed, 167 insertions(+), 1 deletion(-)
>
> diff --git a/libavutil/file_open.c b/libavutil/file_open.c
> index fb64c2e4ee..58a6073353 100644
> --- a/libavutil/file_open.c
> +++ b/libavutil/file_open.c
> @@ -45,7 +45,7 @@ static int win32_open(const char *filename_utf8, int oflag, int pmode)
>     wchar_t *filename_w;
>
>     /* convert UTF-8 to wide chars */
> -    if (utf8towchar(filename_utf8, &filename_w))
> +    if (get_extended_win32_path(filename_utf8, &filename_w))
>         return -1;

Note, the caller expects that if the function returned an error, all 
temporary allocations made by the function have been freed - the caller 
doesn't need to free those allocations.

>     if (!filename_w)
>         goto fallback;
> diff --git a/libavutil/wchar_filename.h b/libavutil/wchar_filename.h
> index 90f082452c..94f8ce54b5 100644
> --- a/libavutil/wchar_filename.h
> +++ b/libavutil/wchar_filename.h
> @@ -40,6 +40,172 @@ static inline int utf8towchar(const char *filename_utf8, wchar_t **filename_w)
>     MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, *filename_w, num_chars);
>     return 0;
> }
> +
> +/**
> + * Checks for extended path prefixes for which normalization needs to be skipped.
> + * see .NET6: PathInternal.IsExtended()
> + */
> +static inline int path_is_extended(const wchar_t *path)
> +{
> +    if (path[0] == L'\\' && (path[1] == L'\\' || path[1] == L'?') && path[2] == L'?' && path[3] == L'\\')
> +        return 1;
> +
> +    return 0;
> +}
> +
> +/**
> + * Checks for a device path prefix.
> + * see .NET6: PathInternal.IsDevicePath()
> + */
> +static inline int path_is_device_path(const wchar_t *path)
> +{
> +    if (path[0] == L'\\' && path[1] == L'\\' && path[2] == L'.' && path[3] == L'\\')
> +        return 1;
> +
> +    return 0;
> +}
> +
> +/**
> + * Performs path normalization by calling GetFullPathNameW().
> + * see .NET6: PathHelper.GetFullPathName()
> + */
> +static inline int get_full_path_name(wchar_t **ppath_w)
> +{
> +    int num_chars;
> +    wchar_t *temp_w;
> +
> +    num_chars = GetFullPathNameW(*ppath_w, 0, NULL, NULL);
> +    if (num_chars <= 0) {
> +        errno = EINVAL;
> +        return -1;
> +    }
> +
> +    temp_w = (wchar_t *)av_calloc(num_chars, sizeof(wchar_t));
> +    if (!temp_w) {
> +        errno = ENOMEM;
> +        return -1;
> +    }
> +
> +    num_chars = GetFullPathNameW(*ppath_w, num_chars, temp_w, NULL);
> +    if (num_chars <= 0) {
> +        errno = EINVAL;
> +        return -1;

In this error handling path, you leak the allocated temp_w

> +    }
> +
> +    av_freep(ppath_w);
> +    *ppath_w = temp_w;
> +
> +    return 0;
> +}
> +
> +/**
> + * Normalizes a Windows file or folder path.
> + * Expansion of short paths (with 8.3 path components) is currently omitted
> + * as it is not required for accessing long paths.
> + * see .NET6: PathHelper.Normalize().
> + */
> +static inline int path_normalize(wchar_t **ppath_w)
> +{
> +    int ret;
> +
> +    if ((ret = get_full_path_name(ppath_w)) < 0)
> +        return ret;
> +
> +    /* What .NET does at this point is to call PathHelper.TryExpandShortFileName()
> +     * in case the path contains a '~' character.
> +     * We don't need to do this as we don't need to normalize the file name
> +     * for presentation, and the extended path prefix works with 8.3 path
> +     * components as well
> +     */
> +    return 0;
> +}
> +
> +/**
> + * Adds an extended path or UNC prefix to longs paths or paths ending
> + * with a space or a dot. (' ' or '.').
> + * This function expects that the path has been normalized before by
> + * calling path_normalize() and it doesn't check whether the path is
> + * actually long (> MAX_PATH).
> + * see .NET6: PathInternal.EnsureExtendedPrefix() *
> + */
> +static inline int add_extended_prefix(wchar_t **ppath_w)
> +{
> +    const wchar_t *unc_prefix           = L"\\\\?\\UNC\\";
> +    const wchar_t *extended_path_prefix = L"\\\\?\\";
> +    const wchar_t *path_w               = *ppath_w;
> +    const size_t len                    = wcslen(path_w);
> +    wchar_t *temp_w;
> +
> +    /* We're skipping the check IsPartiallyQualified() because
> +     * we expect to have called GetFullPathNameW() already. */
> +    if (len < 2 || path_is_extended(*ppath_w) || path_is_device_path(*ppath_w)) {
> +        return 0;
> +    }
> +
> +    if (path_w[0] == L'\\' && path_w[1] == L'\\') {
> +        /* unc_prefix length is 8 plus 1 for terminating zeros,
> +         * we subtract 2 for the leading '\\' of the original path */
> +        temp_w = (wchar_t *)av_calloc(len - 2 + 8 + 1, sizeof(wchar_t));
> +        if (!temp_w) {
> +            errno = ENOMEM;
> +            return -1;
> +        }
> +        wcscpy(temp_w, unc_prefix);
> +        wcscat(temp_w, path_w + 2);
> +    } else {
> +        // The length of extended_path_prefix is 4 plus 1 for terminating zeros
> +        temp_w = (wchar_t *)av_calloc(len + 4 + 1, sizeof(wchar_t));
> +        if (!temp_w) {
> +            errno = ENOMEM;
> +            return -1;
> +        }
> +        wcscpy(temp_w, extended_path_prefix);
> +        wcscat(temp_w, path_w);
> +    }
> +
> +    av_freep(ppath_w);
> +    *ppath_w = temp_w;
> +
> +    return 0;
> +}
> +
> +/**
> + * Converts a file or folder path to wchar_t for use with Windows file
> + * APIs. Paths with extended path prefix (either '\\?\' or \??\') are
> + * left unchanged.
> + * All other paths are normalized and converted to absolute paths.
> + * Longs paths (>= MAX_PATH) are prefixed with the extended path or extended
> + * UNC path prefix.
> + * see .NET6: Path.GetFullPath() and Path.GetFullPathInternal()
> + */
> +static inline int get_extended_win32_path(const char *path, wchar_t **ppath_w)
> +{
> +    int ret;
> +    size_t len;
> +
> +    if ((ret = utf8towchar(path, ppath_w)) < 0)
> +        return ret;
> +
> +    if (path_is_extended(*ppath_w)) {
> +        /* Paths prefixed with '\\?\' or \??\' are considered normalized by definition.
> +         * Windows doesn't normalize those paths and neither should we.
> +         */
> +        return 0;
> +    }
> +
> +    if ((ret = path_normalize(ppath_w)) < 0)
> +        return ret;

If we return an error here, we have already allocated an output in 
ppath_w - but the caller won't clean up such allocations on errors. Thus, 
if we have allocated something here (that wasn't allocated before), we 
must take care to clean it up on errors.


Additionally - with all the references to .NET6, could you add a base url 
somewhere in the code, where one can look up those references? For someone 
not familiar with the .NET ecosystem, I'm not entirely sure where I would 
start.

// Martin

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

  reply	other threads:[~2022-05-24  9:10 UTC|newest]

Thread overview: 83+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-13  9:53 [FFmpeg-devel] [PATCH 0/2] " ffmpegagent
2022-05-13  9:53 ` [FFmpeg-devel] [PATCH 1/2] avutil/wchar_filename, file_open: " softworkz
2022-05-15 19:02   ` nil-admirari
2022-05-15 20:24     ` Soft Works
2022-05-16  8:34       ` nil-admirari
2022-05-13  9:53 ` [FFmpeg-devel] [PATCH 2/2] avformat/os_support: " softworkz
2022-05-15 19:13   ` nil-admirari
2022-05-15 22:14     ` Soft Works
2022-05-16  8:19       ` nil-admirari
2022-05-13 10:02 ` [FFmpeg-devel] [PATCH 0/2] " Soft Works
2022-05-15 19:36 ` nil-admirari
2022-05-15 20:31   ` Soft Works
2022-05-16  8:45     ` nil-admirari
2022-05-17  0:37       ` Soft Works
2022-05-15 22:17 ` [FFmpeg-devel] [PATCH v2 " ffmpegagent
2022-05-15 22:17   ` [FFmpeg-devel] [PATCH v2 1/2] avutil/wchar_filename, file_open: " softworkz
2022-05-16  8:12     ` nil-admirari
2022-05-16 21:14       ` Soft Works
2022-05-17 15:06         ` nil-admirari
2022-05-17 15:28           ` Soft Works
2022-05-17 15:43             ` Soft Works
2022-05-20 17:51               ` nil-admirari
2022-05-20 18:03                 ` Soft Works
2022-05-21 11:08                   ` nil-admirari
2022-05-21 11:12                     ` Soft Works
2022-05-23 15:35                       ` nil-admirari
2022-05-23 15:47                         ` Soft Works
2022-05-23 17:12                           ` Hendrik Leppkes
2022-05-24  5:32                             ` Soft Works
2022-05-24  5:54                               ` Soft Works
2022-05-24  9:47                           ` Soft Works
2022-05-24 12:11                             ` nil-admirari
2022-05-15 22:17   ` [FFmpeg-devel] [PATCH v2 2/2] avformat/os_support: " softworkz
2022-05-16 21:23   ` [FFmpeg-devel] [PATCH v3 0/2] " ffmpegagent
2022-05-16 21:23     ` [FFmpeg-devel] [PATCH v3 1/2] avutil/wchar_filename, file_open: " softworkz
2022-05-16 21:23     ` [FFmpeg-devel] [PATCH v3 2/2] avformat/os_support: " softworkz
2022-05-23 11:29     ` [FFmpeg-devel] [PATCH v4 0/2] " ffmpegagent
2022-05-23 11:29       ` [FFmpeg-devel] [PATCH v4 1/2] avutil/wchar_filename, file_open: " softworkz
2022-05-23 11:29       ` [FFmpeg-devel] [PATCH v4 2/2] avformat/os_support: " softworkz
2022-05-24  8:43       ` [FFmpeg-devel] [PATCH v5 0/2] " ffmpegagent
2022-05-24  8:43         ` [FFmpeg-devel] [PATCH v5 1/2] avutil/wchar_filename, file_open: " softworkz
2022-05-24  9:09           ` Martin Storsjö [this message]
2022-05-24  8:43         ` [FFmpeg-devel] [PATCH v5 2/2] avformat/os_support: " softworkz
2022-05-24  9:23           ` Martin Storsjö
2022-05-24  9:33             ` Soft Works
2022-05-24 10:25               ` Martin Storsjö
2022-05-24 11:15                 ` Soft Works
2022-05-24 11:26                   ` Martin Storsjö
2022-05-24 12:31                     ` Soft Works
2022-05-24 12:44                       ` Martin Storsjö
2022-05-24 13:41                         ` Soft Works
2022-05-24 13:58         ` [FFmpeg-devel] [PATCH v6 0/2] " ffmpegagent
2022-05-24 13:58           ` [FFmpeg-devel] [PATCH v6 1/2] avutil/wchar_filename, file_open: " softworkz
2022-05-24 20:55             ` Martin Storsjö
2022-05-24 13:58           ` [FFmpeg-devel] [PATCH v6 2/2] avformat/os_support: " softworkz
2022-05-24 20:58             ` Martin Storsjö
2022-05-24 22:12               ` Soft Works
2022-05-25  7:09                 ` Martin Storsjö
2022-05-24 22:20           ` [FFmpeg-devel] [PATCH v7 0/3] " ffmpegagent
2022-05-24 22:20             ` [FFmpeg-devel] [PATCH v7 1/3] avutil/wchar_filename, file_open: " softworkz
2022-05-24 22:20             ` [FFmpeg-devel] [PATCH v7 2/3] avformat/os_support: " softworkz
2022-05-25 14:47               ` nil-admirari
2022-05-25 15:28                 ` Soft Works
2022-05-25 19:17                   ` nil-admirari
2022-05-26  5:09                     ` Soft Works
2022-05-25 18:50                 ` Martin Storsjö
2022-05-24 22:20             ` [FFmpeg-devel] [PATCH v7 3/3] avformat/file: remove _WIN32 condition softworkz
2022-05-25  7:34             ` [FFmpeg-devel] [PATCH v7 0/3] Support long file names on Windows Martin Storsjö
2022-05-26  9:28             ` [FFmpeg-devel] [PATCH v8 " ffmpegagent
2022-05-26  9:28               ` [FFmpeg-devel] [PATCH v8 1/3] avutil/wchar_filename, file_open: " softworkz
2022-05-26  9:28               ` [FFmpeg-devel] [PATCH v8 2/3] avformat/os_support: " softworkz
2022-05-26  9:28               ` [FFmpeg-devel] [PATCH v8 3/3] avformat/file: remove _WIN32 condition softworkz
2022-05-26 21:26               ` [FFmpeg-devel] [PATCH v8 0/3] Support long file names on Windows Martin Storsjö
2022-06-09 10:03               ` Martin Storsjö
2022-06-09 19:37                 ` nil-admirari
2022-06-09 20:15                   ` Soft Works
2022-06-09 20:22                     ` nil-admirari
2022-06-09 21:32                     ` Soft Works
2022-06-09 20:21                   ` Martin Storsjö
2022-06-09 20:57                     ` nil-admirari
2022-06-09 21:02                       ` Martin Storsjö
2022-06-13 16:42                         ` nil-admirari
2022-06-09 21:03                       ` Soft Works

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=67674be9-ee2-9918-b3e5-3183633e9ba@martin.st \
    --to=martin@martin.st \
    --cc=ffmpeg-devel@ffmpeg.org \
    --cc=h.leppkes@gmail.com \
    --cc=softworkz@hotmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git