]> cygwin.com Git - cygwin-apps/setup.git/blob - io_stream_cygfile.cc
2002-07-15 Robert Collins <rbtcollins@hotmail.com>
[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 "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"
35 #include "IOStreamProvider.h"
36
37 /* completely private iostream registration class */
38 class CygFileProvider : public IOStreamProvider
39 {
40 public:
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);}
54 protected:
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
61 private:
62 static CygFileProvider theInstance;
63 };
64 CygFileProvider CygFileProvider::theInstance = CygFileProvider();
65
66
67 /* For set mtime */
68 #define FACTOR (0x19db1ded53ea710LL)
69 #define NSPERSEC 10000000LL
70
71 String io_stream_cygfile::cwd("/");
72
73 // Normalise a unix style path relative to
74 // cwd.
75 String
76 io_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
113 static void
114 get_root_dir_now ()
115 {
116 if (get_root_dir ().size())
117 return;
118 read_mounts ();
119 }
120
121 io_stream_cygfile::io_stream_cygfile (String const &name, String const &mode) : fp(), fname()
122 {
123 errno = 0;
124 if (!name.size() || !mode.size())
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 ();
131 if (!get_root_dir ().size())
132 /* TODO: assign a errno for "no mount table :} " */
133 return;
134
135 fname = cygpath (normalise(name));
136 lmode = mode;
137 fp = fopen (fname.cstr_oneuse(), mode.cstr_oneuse());
138 if (!fp)
139 lasterr = errno;
140 }
141
142 io_stream_cygfile::~io_stream_cygfile ()
143 {
144 if (fp)
145 fclose (fp);
146 destroyed = 1;
147 }
148
149 /* Static members */
150 int
151 io_stream_cygfile::exists (String const &path)
152 {
153 get_root_dir_now ();
154 if (get_root_dir ().size() && _access (cygpath (normalise(path)).cstr_oneuse(), 0) == 0)
155 return 1;
156 return 0;
157 }
158
159 int
160 io_stream_cygfile::remove (String const &path)
161 {
162 if (!path.size())
163 return 1;
164 get_root_dir_now ();
165 if (!get_root_dir ().size())
166 /* TODO: assign a errno for "no mount table :} " */
167 return 1;
168
169 unsigned long w = GetFileAttributes (cygpath (normalise(path)).cstr_oneuse());
170 if (w != 0xffffffff && w & FILE_ATTRIBUTE_DIRECTORY)
171 {
172 char tmp[cygpath (normalise(path)).size() + 10];
173 int i = 0;
174 do
175 {
176 ++i;
177 sprintf (tmp, "%s.old-%d", cygpath (normalise(path)).cstr_oneuse(), i);
178 }
179 while (GetFileAttributes (tmp) != 0xffffffff);
180 fprintf (stderr, "warning: moving directory \"%s\" out of the way.\n",
181 normalise(path).cstr_oneuse());
182 MoveFile (cygpath (normalise(path)).cstr_oneuse(), tmp);
183 }
184 return io_stream::remove (String ("file://") + cygpath (normalise(path)).cstr_oneuse());
185 }
186
187 int
188 io_stream_cygfile::mklink (String const &_from, String const &_to,
189 io_stream_link_t linktype)
190 {
191 if (!_from.size() || !_to.size())
192 return 1;
193 String from(normalise(_from));
194 String to (normalise(_to));
195 switch (linktype)
196 {
197 case IO_STREAM_SYMLINK:
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());
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 */
207 io_stream *in = io_stream::open (String ("cygfile://") + to, "rb");
208 if (!in)
209 {
210 log (LOG_TIMESTAMP, String("could not open ") + to +" for reading in mklink");
211 return 1;
212 }
213 io_stream *out = io_stream::open (String ("cygfile://") + from, "wb");
214 if (!out)
215 {
216 log (LOG_TIMESTAMP, String("could not open ") + from + " for writing in mklink");
217 delete in;
218 return 1;
219 }
220
221 if (io_stream::copy (in, out))
222 {
223 log (LOG_TIMESTAMP, String ("Failed to hardlink ")+ from + "->" +to +
224 " during file copy.");
225 delete in;
226 delete out;
227 return 1;
228 }
229 delete in;
230 delete out;
231 return 0;
232 }
233 }
234 return 1;
235 }
236
237
238 /* virtuals */
239
240 ssize_t
241 io_stream_cygfile::read (void *buffer, size_t len)
242 {
243 if (fp)
244 return fread (buffer, 1, len, fp);
245 return 0;
246 }
247
248 ssize_t
249 io_stream_cygfile::write (const void *buffer, size_t len)
250 {
251 if (fp)
252 return fwrite (buffer, 1, len, fp);
253 return 0;
254 }
255
256 ssize_t
257 io_stream_cygfile::peek (void *buffer, size_t len)
258 {
259 if (fp)
260 {
261 int pos = ftell (fp);
262 ssize_t rv = fread (buffer, 1, len, fp);
263 fseek (fp, pos, SEEK_SET);
264 return rv;
265 }
266 return 0;
267 }
268
269 long
270 io_stream_cygfile::tell ()
271 {
272 if (fp)
273 {
274 return ftell (fp);
275 }
276 return 0;
277 }
278
279 int
280 io_stream_cygfile::seek (long where, io_stream_seek_t whence)
281 {
282 if (fp)
283 {
284 return fseek (fp, where, (int) whence);
285 }
286 lasterr = EBADF;
287 return -1;
288 }
289
290 int
291 io_stream_cygfile::error ()
292 {
293 if (fp)
294 return ferror (fp);
295 return lasterr;
296 }
297
298 int
299 cygmkdir_p (enum path_type_t isadir, String const &_name)
300 {
301 if (!_name.size())
302 return 1;
303 String name(io_stream_cygfile::normalise(_name));
304 get_root_dir_now ();
305 if (!get_root_dir ().size())
306 /* TODO: assign a errno for "no mount table :} " */
307 return 1;
308 return mkdir_p (isadir == PATH_TO_DIR ? 1 : 0, cygpath (name).cstr_oneuse());
309 }
310
311 int
312 io_stream_cygfile::set_mtime (int mtime)
313 {
314 if (!fname.size())
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 =
323 CreateFileA (fname.cstr_oneuse(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
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);
330 #if 0
331 fp = fopen (fname, lmode);
332 if (!fp)
333 lasterr = errno;
334 #endif
335 return 0;
336 }
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
341 fp = fopen (fname, lmode);
342 if (!fp)
343 lasterr = errno;
344 #endif
345 return 1;
346 }
347
348 int
349 io_stream_cygfile::move (String const &_from, String const &_to)
350 {
351 if (!_from.size() || !_to.size())
352 return 1;
353 String from (normalise(_from));
354 String to(normalise(_to));
355 get_root_dir_now ();
356 if (!get_root_dir ().size())
357 /* TODO: assign a errno for "no mount table :} " */
358 return 1;
359 return rename (cygpath (from).cstr_oneuse(), cygpath (to).cstr_oneuse());
360 }
361
362 size_t
363 io_stream_cygfile::get_size ()
364 {
365 if (!fname.size() )
366 return 0;
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
389 }
This page took 0.053264 seconds and 5 git commands to generate.