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
=
33 #include "io_stream.h"
34 #include "io_stream_cygfile.h"
35 #include "IOStreamProvider.h"
37 /* completely private iostream registration class */
38 class CygFileProvider
: public IOStreamProvider
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
);}
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
);}
55 CygFileProvider() // no creating this
57 io_stream::registerProvider (theInstance
, "cygfile://");
59 CygFileProvider(CygFileProvider
const &); // no copying
60 CygFileProvider
&operator=(CygFileProvider
const &); // no assignment
62 static CygFileProvider theInstance
;
64 CygFileProvider
CygFileProvider::theInstance
= CygFileProvider();
68 #define FACTOR (0x19db1ded53ea710LL)
69 #define NSPERSEC 10000000LL
71 String
io_stream_cygfile::cwd("/");
73 // Normalise a unix style path relative to
76 io_stream_cygfile::normalise (String
const &unixpath
)
80 if (unixpath
.cstr_oneuse()[0]=='/')
83 path
= unixpath
.cstr();
84 tempout
= unixpath
.cstr(); // paths only shrink.
88 path
= (cwd
+ unixpath
).cstr();
89 tempout
= (cwd
+ unixpath
).cstr(); //paths only shrink.
92 // FIXME: handle .. depth tests to prevent / + ../foo/ stepping out
94 // FIXME: handle /./ sequences
95 bool sawslash
= false;
96 char *outptr
= tempout
;
97 for (char *ptr
=path
; *ptr
; ++ptr
)
99 if (*ptr
== '/' && sawslash
)
101 else if (*ptr
== '/')
116 if (get_root_dir ().size())
121 io_stream_cygfile::io_stream_cygfile (String
const &name
, String
const &mode
) : fp(), fname()
124 if (!name
.size() || !mode
.size())
127 /* do this every time because the mount points may change due to fwd/back button use...
128 * TODO: make this less...manual
131 if (!get_root_dir ().size())
132 /* TODO: assign a errno for "no mount table :} " */
135 fname
= cygpath (normalise(name
));
137 fp
= fopen (fname
.cstr_oneuse(), mode
.cstr_oneuse());
142 io_stream_cygfile::~io_stream_cygfile ()
151 io_stream_cygfile::exists (String
const &path
)
154 if (get_root_dir ().size() && _access (cygpath (normalise(path
)).cstr_oneuse(), 0) == 0)
160 io_stream_cygfile::remove (String
const &path
)
165 if (!get_root_dir ().size())
166 /* TODO: assign a errno for "no mount table :} " */
169 unsigned long w
= GetFileAttributes (cygpath (normalise(path
)).cstr_oneuse());
170 if (w
!= 0xffffffff && w
& FILE_ATTRIBUTE_DIRECTORY
)
172 char tmp
[cygpath (normalise(path
)).size() + 10];
177 sprintf (tmp
, "%s.old-%d", cygpath (normalise(path
)).cstr_oneuse(), i
);
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
);
184 return io_stream::remove (String ("file://") + cygpath (normalise(path
)).cstr_oneuse());
188 io_stream_cygfile::mklink (String
const &_from
, String
const &_to
,
189 io_stream_link_t linktype
)
191 if (!_from
.size() || !_to
.size())
193 String
from(normalise(_from
));
194 String
to (normalise(_to
));
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
:
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?
207 io_stream
*in
= io_stream::open (String ("cygfile://") + to
, "rb");
210 log (LOG_TIMESTAMP
, String("could not open ") + to
+" for reading in mklink");
213 io_stream
*out
= io_stream::open (String ("cygfile://") + from
, "wb");
216 log (LOG_TIMESTAMP
, String("could not open ") + from
+ " for writing in mklink");
221 if (io_stream::copy (in
, out
))
223 log (LOG_TIMESTAMP
, String ("Failed to hardlink ")+ from
+ "->" +to
+
224 " during file copy.");
241 io_stream_cygfile::read (void *buffer
, size_t len
)
244 return fread (buffer
, 1, len
, fp
);
249 io_stream_cygfile::write (const void *buffer
, size_t len
)
252 return fwrite (buffer
, 1, len
, fp
);
257 io_stream_cygfile::peek (void *buffer
, size_t len
)
261 int pos
= ftell (fp
);
262 ssize_t rv
= fread (buffer
, 1, len
, fp
);
263 fseek (fp
, pos
, SEEK_SET
);
270 io_stream_cygfile::tell ()
280 io_stream_cygfile::seek (long where
, io_stream_seek_t whence
)
284 return fseek (fp
, where
, (int) whence
);
291 io_stream_cygfile::error ()
299 cygmkdir_p (enum path_type_t isadir
, String
const &_name
)
303 String
name(io_stream_cygfile::normalise(_name
));
305 if (!get_root_dir ().size())
306 /* TODO: assign a errno for "no mount table :} " */
308 return mkdir_p (isadir
== PATH_TO_DIR
? 1 : 0, cygpath (name
).cstr_oneuse());
312 io_stream_cygfile::set_mtime (int mtime
)
318 long long ftimev
= mtime
* NSPERSEC
+ FACTOR
;
320 ftime
.dwHighDateTime
= ftimev
>> 32;
321 ftime
.dwLowDateTime
= ftimev
;
323 CreateFileA (fname
.cstr_oneuse(), GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
325 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_BACKUP_SEMANTICS
, 0);
328 SetFileTime (h
, 0, 0, &ftime
);
331 fp
= fopen (fname
, lmode
);
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
);
349 io_stream_cygfile::move (String
const &_from
, String
const &_to
)
351 if (!_from
.size() || !_to
.size())
353 String
from (normalise(_from
));
354 String
to(normalise(_to
));
356 if (!get_root_dir ().size())
357 /* TODO: assign a errno for "no mount table :} " */
359 return rename (cygpath (from
).cstr_oneuse(), cygpath (to
).cstr_oneuse());
363 io_stream_cygfile::get_size ()
372 h
= FindFirstFileA (fname
.cstr_oneuse(), &buf
);
373 if (h
!= INVALID_HANDLE_VALUE
)
375 if (buf
.nFileSizeHigh
== 0)
376 ret
= buf
.nFileSizeLow
;
382 /* Should this be lstat? */
383 if (stat (fname
.cstr_oneuse(), &buf
))
384 /* failed - should never happen in this version */
385 /* Throw an exception? */