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
12 * Written by Robert Collins <rbtcollins@hotmail.com>
17 static const char *cvsid
=
32 #include "io_stream.h"
33 #include "io_stream_cygfile.h"
34 #include "IOStreamProvider.h"
36 /* completely private iostream registration class */
37 class CygFileProvider
: public IOStreamProvider
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
);}
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
);}
54 CygFileProvider() // no creating this
56 io_stream::registerProvider (theInstance
, "cygfile://");
58 CygFileProvider(CygFileProvider
const &); // no copying
59 CygFileProvider
&operator=(CygFileProvider
const &); // no assignment
61 static CygFileProvider theInstance
;
63 CygFileProvider
CygFileProvider::theInstance
= CygFileProvider();
67 #define FACTOR (0x19db1ded53ea710LL)
68 #define NSPERSEC 10000000LL
70 String
io_stream_cygfile::cwd("/");
72 // Normalise a unix style path relative to
75 io_stream_cygfile::normalise (String
const &unixpath
)
79 if (unixpath
.cstr_oneuse()[0]=='/')
82 path
= unixpath
.cstr();
83 tempout
= unixpath
.cstr(); // paths only shrink.
87 path
= (cwd
+ unixpath
).cstr();
88 tempout
= (cwd
+ unixpath
).cstr(); //paths only shrink.
91 // FIXME: handle .. depth tests to prevent / + ../foo/ stepping out
93 // FIXME: handle /./ sequences
94 bool sawslash
= false;
95 char *outptr
= tempout
;
96 for (char *ptr
=path
; *ptr
; ++ptr
)
98 if (*ptr
== '/' && sawslash
)
100 else if (*ptr
== '/')
115 if (get_root_dir ().size())
120 io_stream_cygfile::io_stream_cygfile (String
const &name
, String
const &mode
) : fp(), fname()
123 if (!name
.size() || !mode
.size())
126 /* do this every time because the mount points may change due to fwd/back button use...
127 * TODO: make this less...manual
130 if (!get_root_dir ().size())
131 /* TODO: assign a errno for "no mount table :} " */
134 fname
= cygpath (normalise(name
));
136 fp
= fopen (fname
.cstr_oneuse(), mode
.cstr_oneuse());
141 io_stream_cygfile::~io_stream_cygfile ()
149 io_stream_cygfile::exists (String
const &path
)
152 if (get_root_dir ().size() && _access (cygpath (normalise(path
)).cstr_oneuse(), 0) == 0)
158 io_stream_cygfile::remove (String
const &path
)
163 if (!get_root_dir ().size())
164 /* TODO: assign a errno for "no mount table :} " */
167 unsigned long w
= GetFileAttributes (cygpath (normalise(path
)).cstr_oneuse());
168 if (w
!= 0xffffffff && w
& FILE_ATTRIBUTE_DIRECTORY
)
170 char tmp
[cygpath (normalise(path
)).size() + 10];
175 sprintf (tmp
, "%s.old-%d", cygpath (normalise(path
)).cstr_oneuse(), i
);
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
);
182 return io_stream::remove (String ("file://") + cygpath (normalise(path
)).cstr_oneuse());
186 io_stream_cygfile::mklink (String
const &_from
, String
const &_to
,
187 io_stream_link_t linktype
)
189 if (!_from
.size() || !_to
.size())
191 String
from(normalise(_from
));
192 String
to (normalise(_to
));
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
:
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?
205 io_stream
*in
= io_stream::open (String ("cygfile://") + to
, "rb");
208 log (LOG_TIMESTAMP
, String("could not open ") + to
+" for reading in mklink");
211 io_stream
*out
= io_stream::open (String ("cygfile://") + from
, "wb");
214 log (LOG_TIMESTAMP
, String("could not open ") + from
+ " for writing in mklink");
219 if (io_stream::copy (in
, out
))
221 log (LOG_TIMESTAMP
, String ("Failed to hardlink ")+ from
+ "->" +to
+
222 " during file copy.");
239 io_stream_cygfile::read (void *buffer
, size_t len
)
242 return fread (buffer
, 1, len
, fp
);
247 io_stream_cygfile::write (const void *buffer
, size_t len
)
250 return fwrite (buffer
, 1, len
, fp
);
255 io_stream_cygfile::peek (void *buffer
, size_t len
)
259 int pos
= ftell (fp
);
260 ssize_t rv
= fread (buffer
, 1, len
, fp
);
261 fseek (fp
, pos
, SEEK_SET
);
268 io_stream_cygfile::tell ()
278 io_stream_cygfile::seek (long where
, io_stream_seek_t whence
)
282 return fseek (fp
, where
, (int) whence
);
289 io_stream_cygfile::error ()
297 cygmkdir_p (path_type_t isadir
, String
const &_name
)
301 String
name(io_stream_cygfile::normalise(_name
));
303 if (!get_root_dir ().size())
304 /* TODO: assign a errno for "no mount table :} " */
306 return mkdir_p (isadir
== PATH_TO_DIR
? 1 : 0, cygpath (name
).cstr_oneuse());
310 io_stream_cygfile::set_mtime (int mtime
)
316 long long ftimev
= mtime
* NSPERSEC
+ FACTOR
;
318 ftime
.dwHighDateTime
= ftimev
>> 32;
319 ftime
.dwLowDateTime
= ftimev
;
321 CreateFileA (fname
.cstr_oneuse(), GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
323 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_BACKUP_SEMANTICS
, 0);
326 SetFileTime (h
, 0, 0, &ftime
);
329 fp
= fopen (fname
, lmode
);
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
);
347 io_stream_cygfile::move (String
const &_from
, String
const &_to
)
349 if (!_from
.size() || !_to
.size())
351 String
from (normalise(_from
));
352 String
to(normalise(_to
));
354 if (!get_root_dir ().size())
355 /* TODO: assign a errno for "no mount table :} " */
357 return rename (cygpath (from
).cstr_oneuse(), cygpath (to
).cstr_oneuse());
361 io_stream_cygfile::get_size ()
370 h
= FindFirstFileA (fname
.cstr_oneuse(), &buf
);
371 if (h
!= INVALID_HANDLE_VALUE
)
373 if (buf
.nFileSizeHigh
== 0)
374 ret
= buf
.nFileSizeLow
;
380 /* Should this be lstat? */
381 if (stat (fname
.cstr_oneuse(), &buf
))
382 /* failed - should never happen in this version */
383 /* Throw an exception? */