1*600f14f4SXin Li /* grabbag - Convenience lib for various routines common to several tools
2*600f14f4SXin Li * Copyright (C) 2002-2009 Josh Coalson
3*600f14f4SXin Li * Copyright (C) 2011-2023 Xiph.Org Foundation
4*600f14f4SXin Li *
5*600f14f4SXin Li * This library is free software; you can redistribute it and/or
6*600f14f4SXin Li * modify it under the terms of the GNU Lesser General Public
7*600f14f4SXin Li * License as published by the Free Software Foundation; either
8*600f14f4SXin Li * version 2.1 of the License, or (at your option) any later version.
9*600f14f4SXin Li *
10*600f14f4SXin Li * This library is distributed in the hope that it will be useful,
11*600f14f4SXin Li * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*600f14f4SXin Li * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13*600f14f4SXin Li * Lesser General Public License for more details.
14*600f14f4SXin Li *
15*600f14f4SXin Li * You should have received a copy of the GNU Lesser General Public
16*600f14f4SXin Li * License along with this library; if not, write to the Free Software
17*600f14f4SXin Li * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*600f14f4SXin Li */
19*600f14f4SXin Li
20*600f14f4SXin Li #ifdef HAVE_CONFIG_H
21*600f14f4SXin Li # include <config.h>
22*600f14f4SXin Li #endif
23*600f14f4SXin Li
24*600f14f4SXin Li #if defined _MSC_VER || defined __MINGW32__
25*600f14f4SXin Li #include <sys/utime.h> /* for utime() */
26*600f14f4SXin Li #include <io.h> /* for chmod(), _setmode(), unlink() */
27*600f14f4SXin Li #include <fcntl.h> /* for _O_BINARY */
28*600f14f4SXin Li #else
29*600f14f4SXin Li #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
30*600f14f4SXin Li #endif
31*600f14f4SXin Li #if defined __EMX__
32*600f14f4SXin Li #include <io.h> /* for setmode(), O_BINARY */
33*600f14f4SXin Li #include <fcntl.h> /* for _O_BINARY */
34*600f14f4SXin Li #endif
35*600f14f4SXin Li #include <sys/stat.h> /* for stat(), maybe chmod() */
36*600f14f4SXin Li #if defined _WIN32 && !defined __CYGWIN__
37*600f14f4SXin Li #else
38*600f14f4SXin Li #include <unistd.h> /* for unlink() */
39*600f14f4SXin Li #endif
40*600f14f4SXin Li #include <stdio.h>
41*600f14f4SXin Li #include <stdlib.h>
42*600f14f4SXin Li #include <string.h> /* for strrchr() */
43*600f14f4SXin Li #if defined _WIN32 && !defined __CYGWIN__
44*600f14f4SXin Li // for GetFileInformationByHandle() etc
45*600f14f4SXin Li #include <windows.h>
46*600f14f4SXin Li #include <winbase.h>
47*600f14f4SXin Li #endif
48*600f14f4SXin Li #include "share/grabbag.h"
49*600f14f4SXin Li #include "share/compat.h"
50*600f14f4SXin Li
51*600f14f4SXin Li
grabbag__file_copy_metadata(const char * srcpath,const char * destpath)52*600f14f4SXin Li void grabbag__file_copy_metadata(const char *srcpath, const char *destpath)
53*600f14f4SXin Li {
54*600f14f4SXin Li struct flac_stat_s srcstat;
55*600f14f4SXin Li
56*600f14f4SXin Li if(0 == flac_stat(srcpath, &srcstat)) {
57*600f14f4SXin Li #if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) && !defined(_WIN32)
58*600f14f4SXin Li struct timespec srctime[2] = {};
59*600f14f4SXin Li srctime[0].tv_sec = srcstat.st_atime;
60*600f14f4SXin Li srctime[1].tv_sec = srcstat.st_mtime;
61*600f14f4SXin Li #else
62*600f14f4SXin Li struct utimbuf srctime;
63*600f14f4SXin Li srctime.actime = srcstat.st_atime;
64*600f14f4SXin Li srctime.modtime = srcstat.st_mtime;
65*600f14f4SXin Li #endif
66*600f14f4SXin Li (void)flac_chmod(destpath, srcstat.st_mode);
67*600f14f4SXin Li (void)flac_utime(destpath, &srctime);
68*600f14f4SXin Li }
69*600f14f4SXin Li }
70*600f14f4SXin Li
grabbag__file_get_filesize(const char * srcpath)71*600f14f4SXin Li FLAC__off_t grabbag__file_get_filesize(const char *srcpath)
72*600f14f4SXin Li {
73*600f14f4SXin Li struct flac_stat_s srcstat;
74*600f14f4SXin Li
75*600f14f4SXin Li if(0 == flac_stat(srcpath, &srcstat))
76*600f14f4SXin Li return srcstat.st_size;
77*600f14f4SXin Li else
78*600f14f4SXin Li return -1;
79*600f14f4SXin Li }
80*600f14f4SXin Li
grabbag__file_get_basename(const char * srcpath)81*600f14f4SXin Li const char *grabbag__file_get_basename(const char *srcpath)
82*600f14f4SXin Li {
83*600f14f4SXin Li const char *p;
84*600f14f4SXin Li
85*600f14f4SXin Li p = strrchr(srcpath, '/');
86*600f14f4SXin Li if(0 == p) {
87*600f14f4SXin Li #if defined _WIN32 && !defined __CYGWIN__
88*600f14f4SXin Li p = strrchr(srcpath, '\\');
89*600f14f4SXin Li if(0 == p)
90*600f14f4SXin Li #endif
91*600f14f4SXin Li return srcpath;
92*600f14f4SXin Li }
93*600f14f4SXin Li return ++p;
94*600f14f4SXin Li }
95*600f14f4SXin Li
grabbag__file_change_stats(const char * filename,FLAC__bool read_only)96*600f14f4SXin Li FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only)
97*600f14f4SXin Li {
98*600f14f4SXin Li struct flac_stat_s stats;
99*600f14f4SXin Li
100*600f14f4SXin Li if(0 == flac_stat(filename, &stats)) {
101*600f14f4SXin Li #if !defined _MSC_VER && !defined __MINGW32__
102*600f14f4SXin Li if(read_only) {
103*600f14f4SXin Li stats.st_mode &= ~S_IWUSR;
104*600f14f4SXin Li stats.st_mode &= ~S_IWGRP;
105*600f14f4SXin Li stats.st_mode &= ~S_IWOTH;
106*600f14f4SXin Li }
107*600f14f4SXin Li else {
108*600f14f4SXin Li stats.st_mode |= S_IWUSR;
109*600f14f4SXin Li }
110*600f14f4SXin Li #else
111*600f14f4SXin Li if(read_only)
112*600f14f4SXin Li stats.st_mode &= ~S_IWRITE;
113*600f14f4SXin Li else
114*600f14f4SXin Li stats.st_mode |= S_IWRITE;
115*600f14f4SXin Li #endif
116*600f14f4SXin Li if(0 != flac_chmod(filename, stats.st_mode))
117*600f14f4SXin Li return false;
118*600f14f4SXin Li }
119*600f14f4SXin Li else
120*600f14f4SXin Li return false;
121*600f14f4SXin Li
122*600f14f4SXin Li return true;
123*600f14f4SXin Li }
124*600f14f4SXin Li
grabbag__file_are_same(const char * f1,const char * f2)125*600f14f4SXin Li FLAC__bool grabbag__file_are_same(const char *f1, const char *f2)
126*600f14f4SXin Li {
127*600f14f4SXin Li #if defined _WIN32 && !defined __CYGWIN__
128*600f14f4SXin Li #if !defined(WINAPI_FAMILY_PARTITION)
129*600f14f4SXin Li #define WINAPI_FAMILY_PARTITION(x) x
130*600f14f4SXin Li #define WINAPI_PARTITION_DESKTOP 1
131*600f14f4SXin Li #endif
132*600f14f4SXin Li /* see
133*600f14f4SXin Li * http://www.hydrogenaudio.org/forums/index.php?showtopic=49439&pid=444300&st=0
134*600f14f4SXin Li * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/getfileinformationbyhandle.asp
135*600f14f4SXin Li * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/by_handle_file_information_str.asp
136*600f14f4SXin Li * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/createfile.asp
137*600f14f4SXin Li * apparently both the files have to be open at the same time for the comparison to work
138*600f14f4SXin Li */
139*600f14f4SXin Li FLAC__bool same = false;
140*600f14f4SXin Li BY_HANDLE_FILE_INFORMATION info1, info2;
141*600f14f4SXin Li HANDLE h1, h2;
142*600f14f4SXin Li BOOL ok = 1;
143*600f14f4SXin Li h1 = CreateFile_utf8(f1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
144*600f14f4SXin Li h2 = CreateFile_utf8(f2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
145*600f14f4SXin Li if(h1 == INVALID_HANDLE_VALUE || h2 == INVALID_HANDLE_VALUE)
146*600f14f4SXin Li ok = 0;
147*600f14f4SXin Li #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
148*600f14f4SXin Li ok &= GetFileInformationByHandle(h1, &info1);
149*600f14f4SXin Li ok &= GetFileInformationByHandle(h2, &info2);
150*600f14f4SXin Li if(ok)
151*600f14f4SXin Li same =
152*600f14f4SXin Li info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber &&
153*600f14f4SXin Li info1.nFileIndexHigh == info2.nFileIndexHigh &&
154*600f14f4SXin Li info1.nFileIndexLow == info2.nFileIndexLow
155*600f14f4SXin Li ;
156*600f14f4SXin Li #else // !WINAPI_PARTITION_DESKTOP
157*600f14f4SXin Li FILE_ID_INFO id_info1, id_info2;
158*600f14f4SXin Li same = GetFileInformationByHandleEx(h1, FileIdInfo, &id_info1, sizeof (id_info1)) &&
159*600f14f4SXin Li GetFileInformationByHandleEx(h2, FileIdInfo, &id_info2, sizeof (id_info2)) &&
160*600f14f4SXin Li id_info1.VolumeSerialNumber == id_info2.VolumeSerialNumber &&
161*600f14f4SXin Li memcmp(&id_info1.FileId, &id_info2.FileId, sizeof(id_info1.FileId)) == 0;
162*600f14f4SXin Li #endif // !WINAPI_PARTITION_DESKTOP
163*600f14f4SXin Li if(h1 != INVALID_HANDLE_VALUE)
164*600f14f4SXin Li CloseHandle(h1);
165*600f14f4SXin Li if(h2 != INVALID_HANDLE_VALUE)
166*600f14f4SXin Li CloseHandle(h2);
167*600f14f4SXin Li return same;
168*600f14f4SXin Li #else
169*600f14f4SXin Li struct flac_stat_s s1, s2;
170*600f14f4SXin Li return f1 && f2 && flac_stat(f1, &s1) == 0 && flac_stat(f2, &s2) == 0 && s1.st_ino == s2.st_ino && s1.st_dev == s2.st_dev;
171*600f14f4SXin Li #endif
172*600f14f4SXin Li }
173*600f14f4SXin Li
grabbag__file_remove_file(const char * filename)174*600f14f4SXin Li FLAC__bool grabbag__file_remove_file(const char *filename)
175*600f14f4SXin Li {
176*600f14f4SXin Li return grabbag__file_change_stats(filename, /*read_only=*/false) && 0 == flac_unlink(filename);
177*600f14f4SXin Li }
178*600f14f4SXin Li
grabbag__file_get_binary_stdin(void)179*600f14f4SXin Li FILE *grabbag__file_get_binary_stdin(void)
180*600f14f4SXin Li {
181*600f14f4SXin Li /* if something breaks here it is probably due to the presence or
182*600f14f4SXin Li * absence of an underscore before the identifiers 'setmode',
183*600f14f4SXin Li * 'fileno', and/or 'O_BINARY'; check your system header files.
184*600f14f4SXin Li */
185*600f14f4SXin Li #if defined _MSC_VER || defined __MINGW32__
186*600f14f4SXin Li _setmode(_fileno(stdin), _O_BINARY);
187*600f14f4SXin Li #elif defined __EMX__
188*600f14f4SXin Li setmode(fileno(stdin), O_BINARY);
189*600f14f4SXin Li #endif
190*600f14f4SXin Li
191*600f14f4SXin Li return stdin;
192*600f14f4SXin Li }
193*600f14f4SXin Li
grabbag__file_get_binary_stdout(void)194*600f14f4SXin Li FILE *grabbag__file_get_binary_stdout(void)
195*600f14f4SXin Li {
196*600f14f4SXin Li /* if something breaks here it is probably due to the presence or
197*600f14f4SXin Li * absence of an underscore before the identifiers 'setmode',
198*600f14f4SXin Li * 'fileno', and/or 'O_BINARY'; check your system header files.
199*600f14f4SXin Li */
200*600f14f4SXin Li #if defined _MSC_VER || defined __MINGW32__
201*600f14f4SXin Li _setmode(_fileno(stdout), _O_BINARY);
202*600f14f4SXin Li #elif defined __EMX__
203*600f14f4SXin Li setmode(fileno(stdout), O_BINARY);
204*600f14f4SXin Li #endif
205*600f14f4SXin Li
206*600f14f4SXin Li return stdout;
207*600f14f4SXin Li }
208