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".
next prev parent 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