Added translation using Weblate (Italian)
[cygwin-setup.git] / io_stream_cygfile.cc
blob1ee55f5af4ddabb5329a486a806714e5260dea25
1 /*
2 * Copyright (c) 2001, Robert Collins.
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.
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
12 * Written by Robert Collins <rbtcollins@hotmail.com>
16 #include "win32.h"
17 #include "mklink2.h"
18 #include "filemanip.h"
19 #include "mkdir.h"
20 #include "mount.h"
21 #include "compactos.h"
23 #include "getopt++/StringChoiceOption.h"
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <unistd.h>
29 #include "io_stream_cygfile.h"
30 #include "IOStreamProvider.h"
31 #include "LogSingleton.h"
32 #include "resource.h"
34 static 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 });
41 static StringChoiceOption CompactOsOption(algs,
42 '\0', "compact-os", IDS_HELPTEXT_COMPACTOS,
43 true, -1, FILE_PROVIDER_COMPRESSION_LZX);
45 /* completely private iostream registration class */
46 class CygFileProvider : public IOStreamProvider
48 public:
49 int exists (const std::string& path) const
50 {return io_stream_cygfile::exists(path);}
51 int remove (const std::string& path) const
52 {return io_stream_cygfile::remove(path);}
53 int mklink (const std::string& a , const std::string& b, io_stream_link_t c) const
54 {return io_stream_cygfile::mklink(a,b,c);}
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);}
57 ~CygFileProvider (){}
58 int move (const std::string& a,const std::string& b) const
59 {return io_stream_cygfile::move (a, b);}
60 int mkdir_p (path_type_t isadir, const std::string& path, mode_t mode) const
61 {return cygmkdir_p (isadir, path, mode);}
62 protected:
63 CygFileProvider() // no creating this
65 io_stream::registerProvider (theInstance, "cygfile://");
67 CygFileProvider(CygFileProvider const &); // no copying
68 CygFileProvider &operator=(CygFileProvider const &); // no assignment
69 private:
70 static CygFileProvider theInstance;
72 CygFileProvider CygFileProvider::theInstance = CygFileProvider();
75 std::string io_stream_cygfile::cwd("/");
76 bool io_stream_cygfile::compact_os_is_available = (OSMajorVersion () >= 10);
78 // Normalise a unix style path relative to
79 // cwd.
80 std::string
81 io_stream_cygfile::normalise (const std::string& unixpath)
83 char *path,*tempout;
85 if (unixpath.c_str()[0]=='/')
87 // rooted path
88 path = new_cstr_char_array (unixpath);
89 tempout = new_cstr_char_array (unixpath); // paths only shrink.
91 else
93 path = new_cstr_char_array (cwd + unixpath);
94 tempout = new_cstr_char_array (cwd + unixpath); //paths only shrink.
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)
104 if (*ptr == '/' && sawslash)
105 --outptr;
106 else if (*ptr == '/')
107 sawslash=true;
108 else
109 sawslash=false;
110 *outptr++ = *ptr;
112 std::string rv = tempout;
113 delete[] path;
114 delete[] tempout;
115 return rv;
118 wchar_t *
119 io_stream_cygfile::w_str ()
121 if (!wname)
123 wname = new wchar_t [fname.size () + 7];
124 if (wname)
125 mklongpath (wname, fname.c_str (), fname.size () + 7);
127 return wname;
130 static void
131 get_root_dir_now ()
133 if (get_root_dir ().size())
134 return;
135 read_mounts (std::string ());
138 static bool
139 compactos_is_useless (const std::string& name)
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. */
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;
157 io_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)
160 errno = 0;
161 if (!name.size())
163 Log (LOG_TIMESTAMP) << "io_stream_cygfile: Bad parameters" << endLog;
164 return;
167 /* do this every time because the mount points may change due to fwd/back button use...
168 * TODO: make this less...manual
170 get_root_dir_now ();
171 if (!get_root_dir ().size())
173 /* TODO: assign a errno for "no mount table :} " */
174 Log (LOG_TIMESTAMP) << "io_stream_cygfile: Error reading mounts" << endLog;
175 return;
178 fname = cygpath (normalise(name));
179 if (mode.size ())
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);
185 if (!fp)
187 lasterr = errno;
188 Log (LOG_TIMESTAMP) << "io_stream_cygfile: fopen(" << name << ") failed " << errno << " "
189 << strerror(errno) << endLog;
192 if (mode[0] == 'w' && compact_os_is_available && CompactOsOption >= 0
193 && !compactos_is_useless (name))
194 compact_os_algorithm = CompactOsOption;
198 io_stream_cygfile::~io_stream_cygfile ()
200 if (fp)
201 fclose (fp);
202 if (wname)
203 delete [] wname;
206 /* Static members */
208 io_stream_cygfile::exists (const std::string& path)
210 get_root_dir_now ();
211 if (!get_root_dir ().size())
212 return 0;
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)
219 return 1;
220 return 0;
224 io_stream_cygfile::remove (const std::string& path)
226 if (!path.size())
227 return 1;
228 get_root_dir_now ();
229 if (!get_root_dir ().size())
230 /* TODO: assign a errno for "no mount table :} " */
231 return 1;
233 size_t len = cygpath (normalise(path)).size () + 7;
234 WCHAR wpath[len];
235 mklongpath (wpath, cygpath (normalise(path)).c_str (), len);
237 unsigned long w = GetFileAttributesW (wpath);
238 if (w != INVALID_FILE_ATTRIBUTES && w & FILE_ATTRIBUTE_DIRECTORY)
240 len = wcslen (wpath);
241 WCHAR tmp[len + 10];
242 wcscpy (tmp, wpath);
243 int i = 0;
246 ++i;
247 swprintf (tmp + len, L"old-%d", i);
249 while (GetFileAttributesW (tmp) != INVALID_FILE_ATTRIBUTES);
250 Log (LOG_TIMESTAMP) << "warning: moving directory \"" << normalise(path).c_str()
251 << "\" out of the way." << endLog;
252 MoveFileW (wpath, tmp);
254 return io_stream::remove (std::string ("file://") + cygpath (normalise(path)).c_str());
257 /* Returns 0 for success */
259 io_stream_cygfile::mklink (const std::string& _from, const std::string& _to,
260 io_stream_link_t linktype)
262 if (!_from.size() || !_to.size())
263 return 1;
264 std::string from(normalise(_from));
265 std::string to (normalise(_to));
266 switch (linktype)
268 case IO_STREAM_SYMLINK:
269 // symlinks are arbitrary targets, can be anything, and are
270 // not subject to translation
271 return mkcygsymlink (cygpath (from).c_str(), _to.c_str());
272 case IO_STREAM_HARDLINK:
274 /* First try to create a real hardlink. */
275 if (!mkcyghardlink (cygpath (from).c_str(), cygpath (to).c_str ()))
276 return 0;
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. */
283 /* textmode alert: should we translate when linking from an binmode to a
284 text mode mount and vice verca?
286 io_stream *in = io_stream::open (std::string ("cygfile://") + to, "rb", 0);
287 if (!in)
289 Log (LOG_TIMESTAMP) << "could not open " << to
290 << " for reading in mklink" << endLog;
291 return 1;
293 io_stream *out = io_stream::open (std::string ("cygfile://") + from, "wb", 0644);
294 if (!out)
296 Log (LOG_TIMESTAMP) << "could not open " << from
297 << " for writing in mklink" << endLog;
298 delete in;
299 return 1;
302 if (io_stream::copy (in, out))
304 Log (LOG_TIMESTAMP) << "Failed to hardlink " << from << "->"
305 << to << " during file copy." << endLog;
306 delete in;
307 delete out;
308 return 1;
310 delete in;
311 delete out;
312 return 0;
315 return 1;
319 /* virtuals */
321 ssize_t
322 io_stream_cygfile::read (void *buffer, size_t len)
324 ssize_t ret = 0;
326 if (len && fp && !feof (fp))
328 clearerr (fp);
329 size_t fret = fread (buffer, 1, len, fp);
330 if (fret < len && ferror (fp))
332 lasterr = errno;
333 ret = -1;
335 else
336 ret = (ssize_t) fret;
338 return ret;
341 ssize_t
342 io_stream_cygfile::write (const void *buffer, size_t len)
344 ssize_t ret = 0;
346 if (len && fp)
348 clearerr (fp);
349 size_t fret = fwrite (buffer, 1, len, fp);
350 if (fret < len && ferror (fp))
352 lasterr = errno;
353 ret = -1;
355 else
356 ret = (ssize_t) fret;
358 return ret;
361 ssize_t
362 io_stream_cygfile::peek (void *buffer, size_t len)
364 if (fp)
366 off_t pos = ftello (fp);
367 ssize_t rv = read (buffer, len);
368 fseeko (fp, pos, SEEK_SET);
369 return rv;
371 return 0;
374 off_t
375 io_stream_cygfile::tell ()
377 if (fp)
378 return ftello (fp);
380 return 0;
383 off_t
384 io_stream_cygfile::seek (off_t where, io_stream_seek_t whence)
386 if (fp)
388 return fseeko (fp, where, (int) whence);
390 lasterr = EBADF;
391 return -1;
395 io_stream_cygfile::error ()
397 if (fp)
398 return ferror (fp);
399 return lasterr;
403 cygmkdir_p (path_type_t isadir, const std::string& _name, mode_t mode)
405 if (!_name.size())
406 return 1;
407 std::string name(io_stream_cygfile::normalise(_name));
408 get_root_dir_now ();
409 if (!get_root_dir ().size())
410 /* TODO: assign a errno for "no mount table :} " */
411 return 1;
412 return mkdir_p (isadir == PATH_TO_DIR ? 1 : 0, cygpath (name).c_str(), mode);
416 io_stream_cygfile::set_mtime (time_t mtime)
418 if (!fname.size())
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;
426 HANDLE h;
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);
430 if (h == INVALID_HANDLE_VALUE)
431 return 1;
433 if (compact_os_algorithm >= 0)
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)
440 DWORD err = GetLastError();
441 Log (LOG_TIMESTAMP) << "Compact OS disabled after error " << err
442 << " on " << fname << endLog;
443 compact_os_is_available = false;
445 else
446 Log (LOG_BABBLE) << "Compact OS algorithm " << compact_os_algorithm
447 << (rc == 0 ? " not" : "") << " applied to " << fname << endLog;
450 SetFileTime (h, 0, 0, &ftime);
451 CloseHandle (h);
452 return 0;
456 io_stream_cygfile::move (const std::string& _from, const std::string& _to)
458 if (!_from.size() || !_to.size())
459 return 1;
460 std::string from (normalise(_from));
461 std::string to(normalise(_to));
462 get_root_dir_now ();
463 if (!get_root_dir ().size())
464 /* TODO: assign a errno for "no mount table :} " */
465 return 1;
466 return rename (cygpath (from).c_str(), cygpath (to).c_str());
469 size_t
470 io_stream_cygfile::get_size ()
472 if (!fname.size() )
473 return 0;
474 HANDLE h;
475 DWORD ret = 0;
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)
481 ret = GetFileSize (h, NULL);
482 CloseHandle (h);
484 return ret;