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