]> cygwin.com Git - cygwin-apps/setup.git/blame - io_stream_cygfile.cc
2002-07-15 Robert Collins <rbtcollins@hotmail.com>
[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
16#if 0
17static const char *cvsid =
18 "\n%%% $Id$\n";
19#endif
20
21
22#include "win32.h"
23#include <stdio.h>
24#include <stdlib.h>
ca9506cc 25#include <errno.h>
b24c88b3
RC
26#include "log.h"
27#include "port.h"
28#include "mount.h"
29#include "mkdir.h"
30#include "mklink2.h"
31#include <unistd.h>
32
33#include "io_stream.h"
34#include "io_stream_cygfile.h"
19911586
RC
35#include "IOStreamProvider.h"
36
37/* completely private iostream registration class */
38class CygFileProvider : public IOStreamProvider
39{
40public:
41 int exists (String const &path) const
42 {return io_stream_cygfile::exists(path);}
43 int remove (String const &path) const
44 {return io_stream_cygfile::remove(path);}
45 int mklink (String const &a , String const &b, io_stream_link_t c) const
46 {return io_stream_cygfile::mklink(a,b,c);}
47 io_stream *open (String const &a,String const &b) const
48 {return new io_stream_cygfile (a, b);}
49 ~CygFileProvider (){}
50 int move (String const &a,String const &b) const
51 {return io_stream_cygfile::move (a, b);}
52 int mkdir_p (enum path_type_t isadir, String const &path) const
53 {return cygmkdir_p (isadir, path);}
54protected:
55 CygFileProvider() // no creating this
56 {
57 io_stream::registerProvider (theInstance, "cygfile://");
58 }
59 CygFileProvider(CygFileProvider const &); // no copying
60 CygFileProvider &operator=(CygFileProvider const &); // no assignment
61private:
62 static CygFileProvider theInstance;
63};
64CygFileProvider CygFileProvider::theInstance = CygFileProvider();
65
b24c88b3
RC
66
67/* For set mtime */
68#define FACTOR (0x19db1ded53ea710LL)
69#define NSPERSEC 10000000LL
70
f2e49cf8
RC
71String io_stream_cygfile::cwd("/");
72
73// Normalise a unix style path relative to
74// cwd.
75String
76io_stream_cygfile::normalise (String const &unixpath)
77{
78 char *path,*tempout;
79
80 if (unixpath.cstr_oneuse()[0]=='/')
81 {
82 // rooted path
83 path = unixpath.cstr();
84 tempout = unixpath.cstr(); // paths only shrink.
85 }
86 else
87 {
88 path = (cwd + unixpath).cstr();
89 tempout = (cwd + unixpath).cstr(); //paths only shrink.
90 }
91
92 // FIXME: handle .. depth tests to prevent / + ../foo/ stepping out
93 // of the cygwin tree
94 // FIXME: handle /./ sequences
95 bool sawslash = false;
96 char *outptr = tempout;
97 for (char *ptr=path; *ptr; ++ptr)
98 {
99 if (*ptr == '/' && sawslash)
100 --outptr;
101 else if (*ptr == '/')
102 sawslash=true;
103 else
104 sawslash=false;
105 *outptr++ = *ptr;
106 }
107 String rv = tempout;
108 delete[] path;
109 delete[] tempout;
110 return rv;
111}
112
b24c88b3
RC
113static void
114get_root_dir_now ()
115{
3c054baf 116 if (get_root_dir ().size())
b24c88b3
RC
117 return;
118 read_mounts ();
119}
120
3c054baf 121io_stream_cygfile::io_stream_cygfile (String const &name, String const &mode) : fp(), fname()
b24c88b3 122{
b24c88b3 123 errno = 0;
3c054baf 124 if (!name.size() || !mode.size())
b24c88b3
RC
125 return;
126
127 /* do this every time because the mount points may change due to fwd/back button use...
128 * TODO: make this less...manual
129 */
130 get_root_dir_now ();
3c054baf 131 if (!get_root_dir ().size())
b24c88b3
RC
132 /* TODO: assign a errno for "no mount table :} " */
133 return;
134
f2e49cf8 135 fname = cygpath (normalise(name));
3c054baf
RC
136 lmode = mode;
137 fp = fopen (fname.cstr_oneuse(), mode.cstr_oneuse());
b24c88b3
RC
138 if (!fp)
139 lasterr = errno;
140}
141
142io_stream_cygfile::~io_stream_cygfile ()
143{
b24c88b3
RC
144 if (fp)
145 fclose (fp);
e9440f0f 146 destroyed = 1;
b24c88b3
RC
147}
148
149/* Static members */
150int
3c054baf 151io_stream_cygfile::exists (String const &path)
b24c88b3
RC
152{
153 get_root_dir_now ();
f2e49cf8 154 if (get_root_dir ().size() && _access (cygpath (normalise(path)).cstr_oneuse(), 0) == 0)
b24c88b3
RC
155 return 1;
156 return 0;
157}
158
159int
3c054baf 160io_stream_cygfile::remove (String const &path)
b24c88b3 161{
3c054baf 162 if (!path.size())
b24c88b3
RC
163 return 1;
164 get_root_dir_now ();
3c054baf 165 if (!get_root_dir ().size())
b24c88b3
RC
166 /* TODO: assign a errno for "no mount table :} " */
167 return 1;
168
f2e49cf8 169 unsigned long w = GetFileAttributes (cygpath (normalise(path)).cstr_oneuse());
b24c88b3
RC
170 if (w != 0xffffffff && w & FILE_ATTRIBUTE_DIRECTORY)
171 {
f2e49cf8 172 char tmp[cygpath (normalise(path)).size() + 10];
b24c88b3
RC
173 int i = 0;
174 do
175 {
3c054baf 176 ++i;
f2e49cf8 177 sprintf (tmp, "%s.old-%d", cygpath (normalise(path)).cstr_oneuse(), i);
b24c88b3
RC
178 }
179 while (GetFileAttributes (tmp) != 0xffffffff);
180 fprintf (stderr, "warning: moving directory \"%s\" out of the way.\n",
f2e49cf8
RC
181 normalise(path).cstr_oneuse());
182 MoveFile (cygpath (normalise(path)).cstr_oneuse(), tmp);
b24c88b3 183 }
4849e2fc 184 return io_stream::remove (String ("file://") + cygpath (normalise(path)).cstr_oneuse());
b24c88b3
RC
185}
186
187int
f2e49cf8 188io_stream_cygfile::mklink (String const &_from, String const &_to,
b24c88b3
RC
189 io_stream_link_t linktype)
190{
f2e49cf8 191 if (!_from.size() || !_to.size())
b24c88b3 192 return 1;
f2e49cf8
RC
193 String from(normalise(_from));
194 String to (normalise(_to));
b24c88b3
RC
195 switch (linktype)
196 {
197 case IO_STREAM_SYMLINK:
f2e49cf8
RC
198 // symlinks are arbitrary targets, can be anything, and are
199 // not subject to translation
200 return mkcygsymlink (cygpath (from).cstr_oneuse(), _to.cstr_oneuse());
b24c88b3
RC
201 case IO_STREAM_HARDLINK:
202 {
203 /* For now, just copy */
204 /* textmode alert: should we translate when linking from an binmode to a
205 text mode mount and vice verca?
206 */
2fa7c5a4 207 io_stream *in = io_stream::open (String ("cygfile://") + to, "rb");
b24c88b3
RC
208 if (!in)
209 {
3c054baf 210 log (LOG_TIMESTAMP, String("could not open ") + to +" for reading in mklink");
b24c88b3
RC
211 return 1;
212 }
2fa7c5a4 213 io_stream *out = io_stream::open (String ("cygfile://") + from, "wb");
b24c88b3
RC
214 if (!out)
215 {
2fa7c5a4 216 log (LOG_TIMESTAMP, String("could not open ") + from + " for writing in mklink");
b24c88b3
RC
217 delete in;
218 return 1;
219 }
220
3c054baf 221 if (io_stream::copy (in, out))
b24c88b3 222 {
3c054baf
RC
223 log (LOG_TIMESTAMP, String ("Failed to hardlink ")+ from + "->" +to +
224 " during file copy.");
225 delete in;
226 delete out;
227 return 1;
b24c88b3
RC
228 }
229 delete in;
230 delete out;
3c054baf 231 return 0;
b24c88b3
RC
232 }
233 }
234 return 1;
235}
236
237
238/* virtuals */
239
7c7034e8
RC
240ssize_t
241io_stream_cygfile::read (void *buffer, size_t len)
b24c88b3
RC
242{
243 if (fp)
244 return fread (buffer, 1, len, fp);
245 return 0;
246}
247
7c7034e8
RC
248ssize_t
249io_stream_cygfile::write (const void *buffer, size_t len)
b24c88b3
RC
250{
251 if (fp)
252 return fwrite (buffer, 1, len, fp);
253 return 0;
254}
255
7c7034e8
RC
256ssize_t
257io_stream_cygfile::peek (void *buffer, size_t len)
b24c88b3 258{
b24c88b3
RC
259 if (fp)
260 {
7c7034e8
RC
261 int pos = ftell (fp);
262 ssize_t rv = fread (buffer, 1, len, fp);
b24c88b3
RC
263 fseek (fp, pos, SEEK_SET);
264 return rv;
265 }
266 return 0;
267}
268
269long
270io_stream_cygfile::tell ()
271{
272 if (fp)
273 {
274 return ftell (fp);
275 }
276 return 0;
277}
278
ca9506cc
RC
279int
280io_stream_cygfile::seek (long where, io_stream_seek_t whence)
281{
282 if (fp)
7c7034e8
RC
283 {
284 return fseek (fp, where, (int) whence);
285 }
ca9506cc
RC
286 lasterr = EBADF;
287 return -1;
288}
289
b24c88b3
RC
290int
291io_stream_cygfile::error ()
292{
293 if (fp)
294 return ferror (fp);
295 return lasterr;
296}
297
298int
f2e49cf8 299cygmkdir_p (enum path_type_t isadir, String const &_name)
b24c88b3 300{
f2e49cf8 301 if (!_name.size())
b24c88b3 302 return 1;
f2e49cf8 303 String name(io_stream_cygfile::normalise(_name));
b24c88b3 304 get_root_dir_now ();
3c054baf 305 if (!get_root_dir ().size())
b24c88b3
RC
306 /* TODO: assign a errno for "no mount table :} " */
307 return 1;
1ac649ed 308 return mkdir_p (isadir == PATH_TO_DIR ? 1 : 0, cygpath (name).cstr_oneuse());
b24c88b3
RC
309}
310
b24c88b3
RC
311int
312io_stream_cygfile::set_mtime (int mtime)
313{
3c054baf 314 if (!fname.size())
b24c88b3
RC
315 return 1;
316 if (fp)
317 fclose (fp);
318 long long ftimev = mtime * NSPERSEC + FACTOR;
319 FILETIME ftime;
320 ftime.dwHighDateTime = ftimev >> 32;
321 ftime.dwLowDateTime = ftimev;
322 HANDLE h =
3c054baf 323 CreateFileA (fname.cstr_oneuse(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
b24c88b3
RC
324 0, OPEN_EXISTING,
325 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
326 if (h)
327 {
328 SetFileTime (h, 0, 0, &ftime);
329 CloseHandle (h);
bb849dbd 330#if 0
b24c88b3
RC
331 fp = fopen (fname, lmode);
332 if (!fp)
333 lasterr = errno;
bb849dbd 334#endif
b24c88b3
RC
335 return 0;
336 }
bb849dbd
RC
337#if 0
338// this results in truncated files.
339// also, semantically, it's nonsense, you cannot write to a file after setting the
340// mtime without changing the mtime
b24c88b3
RC
341 fp = fopen (fname, lmode);
342 if (!fp)
343 lasterr = errno;
bb849dbd 344#endif
b24c88b3
RC
345 return 1;
346}
7c7034e8
RC
347
348int
f2e49cf8 349io_stream_cygfile::move (String const &_from, String const &_to)
7c7034e8 350{
f2e49cf8 351 if (!_from.size() || !_to.size())
7c7034e8 352 return 1;
f2e49cf8
RC
353 String from (normalise(_from));
354 String to(normalise(_to));
7c7034e8 355 get_root_dir_now ();
3c054baf 356 if (!get_root_dir ().size())
7c7034e8
RC
357 /* TODO: assign a errno for "no mount table :} " */
358 return 1;
1ac649ed 359 return rename (cygpath (from).cstr_oneuse(), cygpath (to).cstr_oneuse());
7c7034e8 360}
341988b9
RC
361
362size_t
363io_stream_cygfile::get_size ()
364{
3c054baf 365 if (!fname.size() )
341988b9 366 return 0;
e0a4db64
RC
367#ifdef WIN32
368 HANDLE h;
369 WIN32_FIND_DATA buf;
370 DWORD ret = 0;
371
372 h = FindFirstFileA (fname.cstr_oneuse(), &buf);
373 if (h != INVALID_HANDLE_VALUE)
374 {
375 if (buf.nFileSizeHigh == 0)
376 ret = buf.nFileSizeLow;
377 FindClose (h);
378 }
379 return ret;
380#else
381 struct stat buf;
382 /* Should this be lstat? */
383 if (stat (fname.cstr_oneuse(), &buf))
384 /* failed - should never happen in this version */
385 /* Throw an exception? */
386 return 0;
387 return buf.off_t;
388#endif
341988b9 389}
This page took 0.071098 seconds and 5 git commands to generate.