]> cygwin.com Git - cygwin-apps/setup.git/blame - io_stream_cygfile.cc
Added dpiAwareness element to manifest
[cygwin-apps/setup.git] / io_stream_cygfile.cc
CommitLineData
b24c88b3
RC
1/*
2 * Copyright (c) 2001, Robert Collins.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Robert Collins <rbtcollins@hotmail.com>
13 *
14 */
15
b24c88b3 16#include "win32.h"
45bbb3d4
CV
17#include "mklink2.h"
18#include "filemanip.h"
19#include "mkdir.h"
20#include "mount.h"
b6dab3ea
CF
21#include "compactos.h"
22
94c4c95d 23#include "getopt++/StringChoiceOption.h"
45bbb3d4 24
b24c88b3 25#include <stdlib.h>
ca9506cc 26#include <errno.h>
b24c88b3
RC
27#include <unistd.h>
28
45bbb3d4 29#include "io_stream_cygfile.h"
19911586 30#include "IOStreamProvider.h"
45bbb3d4 31#include "LogSingleton.h"
20f237b4 32#include "resource.h"
45bbb3d4 33
94c4c95d
JT
34static StringChoiceOption::StringChoices algs({
35 {"xpress4k", FILE_PROVIDER_COMPRESSION_XPRESS4K},
36 {"xpress8k", FILE_PROVIDER_COMPRESSION_XPRESS8K},
37 {"xpress16k", FILE_PROVIDER_COMPRESSION_XPRESS16K},
38 {"lzx", FILE_PROVIDER_COMPRESSION_LZX},
39 });
40
41static StringChoiceOption CompactOsOption(algs,
20f237b4 42 '\0', "compact-os", IDS_HELPTEXT_COMPACTOS,
94c4c95d 43 true, -1, FILE_PROVIDER_COMPRESSION_LZX);
19911586
RC
44
45/* completely private iostream registration class */
46class CygFileProvider : public IOStreamProvider
47{
48public:
a3a02820 49 int exists (const std::string& path) const
19911586 50 {return io_stream_cygfile::exists(path);}
a3a02820 51 int remove (const std::string& path) const
19911586 52 {return io_stream_cygfile::remove(path);}
a3a02820 53 int mklink (const std::string& a , const std::string& b, io_stream_link_t c) const
19911586 54 {return io_stream_cygfile::mklink(a,b,c);}
26922cd2
CV
55 io_stream *open (const std::string& a,const std::string& b, mode_t m) const
56 {return new io_stream_cygfile (a, b, m);}
19911586 57 ~CygFileProvider (){}
a3a02820 58 int move (const std::string& a,const std::string& b) const
19911586 59 {return io_stream_cygfile::move (a, b);}
b41c2908
CV
60 int mkdir_p (path_type_t isadir, const std::string& path, mode_t mode) const
61 {return cygmkdir_p (isadir, path, mode);}
19911586
RC
62protected:
63 CygFileProvider() // no creating this
64 {
65 io_stream::registerProvider (theInstance, "cygfile://");
66 }
67 CygFileProvider(CygFileProvider const &); // no copying
68 CygFileProvider &operator=(CygFileProvider const &); // no assignment
69private:
70 static CygFileProvider theInstance;
71};
72CygFileProvider CygFileProvider::theInstance = CygFileProvider();
73
b24c88b3 74
a3a02820 75std::string io_stream_cygfile::cwd("/");
b6dab3ea
CF
76bool io_stream_cygfile::compact_os_is_available = (OSMajorVersion () >= 10);
77
f2e49cf8
RC
78// Normalise a unix style path relative to
79// cwd.
a3a02820
MB
80std::string
81io_stream_cygfile::normalise (const std::string& unixpath)
f2e49cf8
RC
82{
83 char *path,*tempout;
84
d2a3615c 85 if (unixpath.c_str()[0]=='/')
f2e49cf8
RC
86 {
87 // rooted path
3a8630fd
MB
88 path = new_cstr_char_array (unixpath);
89 tempout = new_cstr_char_array (unixpath); // paths only shrink.
f2e49cf8
RC
90 }
91 else
92 {
3a8630fd
MB
93 path = new_cstr_char_array (cwd + unixpath);
94 tempout = new_cstr_char_array (cwd + unixpath); //paths only shrink.
f2e49cf8
RC
95 }
96
97 // FIXME: handle .. depth tests to prevent / + ../foo/ stepping out
98 // of the cygwin tree
99 // FIXME: handle /./ sequences
100 bool sawslash = false;
101 char *outptr = tempout;
102 for (char *ptr=path; *ptr; ++ptr)
103 {
104 if (*ptr == '/' && sawslash)
105 --outptr;
106 else if (*ptr == '/')
107 sawslash=true;
108 else
109 sawslash=false;
110 *outptr++ = *ptr;
111 }
a3a02820 112 std::string rv = tempout;
f2e49cf8
RC
113 delete[] path;
114 delete[] tempout;
115 return rv;
116}
117
2f0315ad
CV
118wchar_t *
119io_stream_cygfile::w_str ()
120{
121 if (!wname)
122 {
123 wname = new wchar_t [fname.size () + 7];
124 if (wname)
125 mklongpath (wname, fname.c_str (), fname.size () + 7);
126 }
127 return wname;
128}
129
b24c88b3
RC
130static void
131get_root_dir_now ()
132{
3c054baf 133 if (get_root_dir ().size())
b24c88b3 134 return;
2f0315ad 135 read_mounts (std::string ());
b24c88b3
RC
136}
137
b6dab3ea
CF
138static bool
139compactos_is_useless (const std::string& name)
140{
141 const char * const p = name.c_str();
142 if (!(!strncmp (p, "/bin/", 5) || !strncmp (p, "/sbin/", 6) || !strncmp (p, "/usr/", 5)))
143 return true; /* File is not in R/O tree. */
144 const size_t len = name.size(); /* >= 5 */
145 if (!strcmp (p + (len - 4), ".dll") || !strcmp (p + (len - 3), ".so")) {
146 if ((len >= 5 + 11 && !strcmp (p + (len - 11), "cygwin1.dll"))
147 || strstr (p + 5, "/sys-root/mingw/"))
148 return false; /* Ignored by rebase. */
149 return true; /* Rebase will open file for writing which uncompresses the file. */
150 }
151 if (!strcmp (p + (len - 4), ".bz2") || !strcmp (p + (len - 3), ".gz")
152 || !strcmp (p + (len - 3), ".xz"))
153 return true; /* File is already compressed. */
154 return false;
155}
156
157io_stream_cygfile::io_stream_cygfile (const std::string& name, const std::string& mode, mode_t perms)
158: fp(), lasterr (0), fname(), wname (NULL), compact_os_algorithm(-1)
b24c88b3 159{
b24c88b3 160 errno = 0;
6dcfeb7d 161 if (!name.size())
db165a9a 162 {
157dc2b8 163 Log (LOG_TIMESTAMP) << "io_stream_cygfile: Bad parameters" << endLog;
b24c88b3 164 return;
db165a9a 165 }
b24c88b3
RC
166
167 /* do this every time because the mount points may change due to fwd/back button use...
168 * TODO: make this less...manual
169 */
170 get_root_dir_now ();
3c054baf 171 if (!get_root_dir ().size())
db165a9a 172 {
b24c88b3 173 /* TODO: assign a errno for "no mount table :} " */
157dc2b8 174 Log (LOG_TIMESTAMP) << "io_stream_cygfile: Error reading mounts" << endLog;
b24c88b3 175 return;
db165a9a 176 }
b24c88b3 177
f2e49cf8 178 fname = cygpath (normalise(name));
6dcfeb7d 179 if (mode.size ())
2f0315ad 180 {
1e029da2
YS
181 if (fname.rfind (".exe") != std::string::npos
182 || fname.rfind (".dll") != std::string::npos)
183 perms |= 0111; /* Make .exe and .dll always executable. */
184 fp = nt_wfopen (w_str(), mode.c_str (), perms);
6dcfeb7d
CV
185 if (!fp)
186 {
187 lasterr = errno;
157dc2b8 188 Log (LOG_TIMESTAMP) << "io_stream_cygfile: fopen(" << name << ") failed " << errno << " "
6dcfeb7d
CV
189 << strerror(errno) << endLog;
190 }
b6dab3ea
CF
191
192 if (mode[0] == 'w' && compact_os_is_available && CompactOsOption >= 0
193 && !compactos_is_useless (name))
194 compact_os_algorithm = CompactOsOption;
2f0315ad 195 }
b24c88b3
RC
196}
197
198io_stream_cygfile::~io_stream_cygfile ()
199{
b24c88b3
RC
200 if (fp)
201 fclose (fp);
2f0315ad
CV
202 if (wname)
203 delete [] wname;
b24c88b3
RC
204}
205
206/* Static members */
207int
a3a02820 208io_stream_cygfile::exists (const std::string& path)
b24c88b3
RC
209{
210 get_root_dir_now ();
2f0315ad
CV
211 if (!get_root_dir ().size())
212 return 0;
213
1e029da2
YS
214 size_t len = cygpath (normalise(path)).size () + 7;
215 WCHAR wname[len];
216 mklongpath (wname, cygpath (normalise(path)).c_str (), len);
217 DWORD attr = GetFileAttributesW (wname);
218 if (attr != INVALID_FILE_ATTRIBUTES)
b24c88b3
RC
219 return 1;
220 return 0;
221}
222
223int
a3a02820 224io_stream_cygfile::remove (const std::string& path)
b24c88b3 225{
3c054baf 226 if (!path.size())
b24c88b3
RC
227 return 1;
228 get_root_dir_now ();
3c054baf 229 if (!get_root_dir ().size())
b24c88b3
RC
230 /* TODO: assign a errno for "no mount table :} " */
231 return 1;
232
1e029da2
YS
233 size_t len = cygpath (normalise(path)).size () + 7;
234 WCHAR wpath[len];
235 mklongpath (wpath, cygpath (normalise(path)).c_str (), len);
236
237 unsigned long w = GetFileAttributesW (wpath);
238 if (w != INVALID_FILE_ATTRIBUTES && w & FILE_ATTRIBUTE_DIRECTORY)
b24c88b3 239 {
1e029da2
YS
240 len = wcslen (wpath);
241 WCHAR tmp[len + 10];
242 wcscpy (tmp, wpath);
243 int i = 0;
244 do
245 {
246 ++i;
247 swprintf (tmp + len, L"old-%d", i);
b24c88b3 248 }
1e029da2 249 while (GetFileAttributesW (tmp) != INVALID_FILE_ATTRIBUTES);
781a9555
JT
250 Log (LOG_TIMESTAMP) << "warning: moving directory \"" << normalise(path).c_str()
251 << "\" out of the way." << endLog;
1e029da2 252 MoveFileW (wpath, tmp);
b24c88b3 253 }
a3a02820 254 return io_stream::remove (std::string ("file://") + cygpath (normalise(path)).c_str());
b24c88b3
RC
255}
256
a5104a04 257/* Returns 0 for success */
b24c88b3 258int
a3a02820 259io_stream_cygfile::mklink (const std::string& _from, const std::string& _to,
b24c88b3
RC
260 io_stream_link_t linktype)
261{
f2e49cf8 262 if (!_from.size() || !_to.size())
b24c88b3 263 return 1;
a3a02820
MB
264 std::string from(normalise(_from));
265 std::string to (normalise(_to));
b24c88b3
RC
266 switch (linktype)
267 {
268 case IO_STREAM_SYMLINK:
f2e49cf8
RC
269 // symlinks are arbitrary targets, can be anything, and are
270 // not subject to translation
d2a3615c 271 return mkcygsymlink (cygpath (from).c_str(), _to.c_str());
b24c88b3
RC
272 case IO_STREAM_HARDLINK:
273 {
d2e8d256
CV
274 /* First try to create a real hardlink. */
275 if (!mkcyghardlink (cygpath (from).c_str(), cygpath (to).c_str ()))
276 return 0;
277
278 /* If creating a hardlink failed, we're probably on a filesystem
279 which doesn't support hardlinks. If so, we also don't care for
280 permissions for now. The filesystem is probably a filesystem
281 which doesn't support ACLs anyway. */
282
b24c88b3
RC
283 /* textmode alert: should we translate when linking from an binmode to a
284 text mode mount and vice verca?
285 */
26922cd2 286 io_stream *in = io_stream::open (std::string ("cygfile://") + to, "rb", 0);
b24c88b3
RC
287 if (!in)
288 {
157dc2b8 289 Log (LOG_TIMESTAMP) << "could not open " << to
a77b6167 290 << " for reading in mklink" << endLog;
b24c88b3
RC
291 return 1;
292 }
26922cd2 293 io_stream *out = io_stream::open (std::string ("cygfile://") + from, "wb", 0644);
b24c88b3
RC
294 if (!out)
295 {
157dc2b8 296 Log (LOG_TIMESTAMP) << "could not open " << from
a77b6167 297 << " for writing in mklink" << endLog;
b24c88b3
RC
298 delete in;
299 return 1;
300 }
301
3c054baf 302 if (io_stream::copy (in, out))
b24c88b3 303 {
157dc2b8 304 Log (LOG_TIMESTAMP) << "Failed to hardlink " << from << "->"
a77b6167 305 << to << " during file copy." << endLog;
3c054baf
RC
306 delete in;
307 delete out;
308 return 1;
b24c88b3
RC
309 }
310 delete in;
311 delete out;
3c054baf 312 return 0;
b24c88b3
RC
313 }
314 }
315 return 1;
316}
317
318
319/* virtuals */
320
7c7034e8
RC
321ssize_t
322io_stream_cygfile::read (void *buffer, size_t len)
b24c88b3 323{
4e30c4f6
CV
324 ssize_t ret = 0;
325
326 if (len && fp && !feof (fp))
327 {
328 clearerr (fp);
329 size_t fret = fread (buffer, 1, len, fp);
330 if (fret < len && ferror (fp))
331 {
332 lasterr = errno;
333 ret = -1;
334 }
335 else
336 ret = (ssize_t) fret;
337 }
338 return ret;
b24c88b3
RC
339}
340
7c7034e8
RC
341ssize_t
342io_stream_cygfile::write (const void *buffer, size_t len)
b24c88b3 343{
4e30c4f6
CV
344 ssize_t ret = 0;
345
346 if (len && fp)
347 {
348 clearerr (fp);
349 size_t fret = fwrite (buffer, 1, len, fp);
350 if (fret < len && ferror (fp))
351 {
352 lasterr = errno;
353 ret = -1;
354 }
355 else
356 ret = (ssize_t) fret;
357 }
358 return ret;
b24c88b3
RC
359}
360
7c7034e8
RC
361ssize_t
362io_stream_cygfile::peek (void *buffer, size_t len)
b24c88b3 363{
b24c88b3
RC
364 if (fp)
365 {
44d31ea0 366 off_t pos = ftello (fp);
64a12e7e 367 ssize_t rv = read (buffer, len);
44d31ea0 368 fseeko (fp, pos, SEEK_SET);
b24c88b3
RC
369 return rv;
370 }
371 return 0;
372}
373
44d31ea0 374off_t
b24c88b3
RC
375io_stream_cygfile::tell ()
376{
377 if (fp)
44d31ea0
CV
378 return ftello (fp);
379
b24c88b3
RC
380 return 0;
381}
382
44d31ea0
CV
383off_t
384io_stream_cygfile::seek (off_t where, io_stream_seek_t whence)
ca9506cc
RC
385{
386 if (fp)
7c7034e8 387 {
44d31ea0 388 return fseeko (fp, where, (int) whence);
7c7034e8 389 }
ca9506cc
RC
390 lasterr = EBADF;
391 return -1;
392}
393
b24c88b3
RC
394int
395io_stream_cygfile::error ()
396{
397 if (fp)
398 return ferror (fp);
399 return lasterr;
400}
401
402int
b41c2908 403cygmkdir_p (path_type_t isadir, const std::string& _name, mode_t mode)
b24c88b3 404{
f2e49cf8 405 if (!_name.size())
b24c88b3 406 return 1;
a3a02820 407 std::string name(io_stream_cygfile::normalise(_name));
b24c88b3 408 get_root_dir_now ();
3c054baf 409 if (!get_root_dir ().size())
b24c88b3
RC
410 /* TODO: assign a errno for "no mount table :} " */
411 return 1;
b41c2908 412 return mkdir_p (isadir == PATH_TO_DIR ? 1 : 0, cygpath (name).c_str(), mode);
b24c88b3
RC
413}
414
b24c88b3 415int
26922cd2 416io_stream_cygfile::set_mtime (time_t mtime)
b24c88b3 417{
3c054baf 418 if (!fname.size())
b24c88b3
RC
419 return 1;
420 if (fp)
421 fclose (fp);
422 long long ftimev = mtime * NSPERSEC + FACTOR;
423 FILETIME ftime;
424 ftime.dwHighDateTime = ftimev >> 32;
425 ftime.dwLowDateTime = ftimev;
2f0315ad 426 HANDLE h;
1e029da2
YS
427 h = CreateFileW (w_str (), GENERIC_WRITE,
428 FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
429 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
21aa9a8b 430 if (h == INVALID_HANDLE_VALUE)
26922cd2 431 return 1;
b6dab3ea
CF
432
433 if (compact_os_algorithm >= 0)
434 {
435 /* Compact OS must be applied after last WriteFile()
436 and before SetFileTime(). */
437 int rc = CompactOsCompressFile (h, compact_os_algorithm);
438 if (rc < 0)
439 {
440 DWORD err = GetLastError();
441 Log (LOG_TIMESTAMP) << "Compact OS disabled after error " << err
442 << " on " << fname << endLog;
443 compact_os_is_available = false;
444 }
445 else
446 Log (LOG_BABBLE) << "Compact OS algorithm " << compact_os_algorithm
447 << (rc == 0 ? " not" : "") << " applied to " << fname << endLog;
448 }
449
21aa9a8b 450 SetFileTime (h, 0, 0, &ftime);
21aa9a8b
CV
451 CloseHandle (h);
452 return 0;
b24c88b3 453}
7c7034e8
RC
454
455int
a3a02820 456io_stream_cygfile::move (const std::string& _from, const std::string& _to)
7c7034e8 457{
f2e49cf8 458 if (!_from.size() || !_to.size())
7c7034e8 459 return 1;
a3a02820
MB
460 std::string from (normalise(_from));
461 std::string to(normalise(_to));
7c7034e8 462 get_root_dir_now ();
3c054baf 463 if (!get_root_dir ().size())
7c7034e8
RC
464 /* TODO: assign a errno for "no mount table :} " */
465 return 1;
d2a3615c 466 return rename (cygpath (from).c_str(), cygpath (to).c_str());
7c7034e8 467}
341988b9
RC
468
469size_t
470io_stream_cygfile::get_size ()
471{
3c054baf 472 if (!fname.size() )
341988b9 473 return 0;
e0a4db64 474 HANDLE h;
e0a4db64 475 DWORD ret = 0;
1e029da2
YS
476 h = CreateFileW (w_str (), GENERIC_READ,
477 FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
478 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
479 if (h != INVALID_HANDLE_VALUE)
e0a4db64 480 {
1e029da2
YS
481 ret = GetFileSize (h, NULL);
482 CloseHandle (h);
e0a4db64
RC
483 }
484 return ret;
341988b9 485}
This page took 0.364288 seconds and 6 git commands to generate.