Sync with trunk rev.61910 to get latest improvements and bugfixes.
[reactos.git] / dll / win32 / scrrun / filesystem.c
1 /*
2 * Copyright 2012 Alistair Leslie-Hughes
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "scrrun_private.h"
20
21 #include <winver.h>
22 #include <olectl.h>
23 #include <ntsecapi.h>
24 #include <wine/unicode.h>
25
26 struct folder {
27 IFolder IFolder_iface;
28 LONG ref;
29 };
30
31 struct file {
32 IFile IFile_iface;
33 LONG ref;
34
35 WCHAR *path;
36 };
37
38 struct textstream {
39 ITextStream ITextStream_iface;
40 LONG ref;
41
42 IOMode mode;
43 };
44
45 enum iotype {
46 IORead,
47 IOWrite
48 };
49
50 static inline struct folder *impl_from_IFolder(IFolder *iface)
51 {
52 return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
53 }
54
55 static inline struct file *impl_from_IFile(IFile *iface)
56 {
57 return CONTAINING_RECORD(iface, struct file, IFile_iface);
58 }
59
60 static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
61 {
62 return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
63 }
64
65 static inline HRESULT create_error(DWORD err)
66 {
67 switch(err) {
68 case ERROR_FILE_NOT_FOUND: return CTL_E_FILENOTFOUND;
69 case ERROR_PATH_NOT_FOUND: return CTL_E_PATHNOTFOUND;
70 case ERROR_ACCESS_DENIED: return CTL_E_PERMISSIONDENIED;
71 case ERROR_FILE_EXISTS: return CTL_E_FILEALREADYEXISTS;
72 case ERROR_ALREADY_EXISTS: return CTL_E_FILEALREADYEXISTS;
73 default:
74 FIXME("Unsupported error code: %d\n", err);
75 return E_FAIL;
76 }
77 }
78
79 static int textstream_check_iomode(struct textstream *This, enum iotype type)
80 {
81 if (type == IORead)
82 return This->mode == ForWriting || This->mode == ForAppending;
83 else
84 return 1;
85 }
86
87 static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
88 {
89 struct textstream *This = impl_from_ITextStream(iface);
90
91 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
92
93 if (IsEqualIID(riid, &IID_ITextStream) ||
94 IsEqualIID(riid, &IID_IDispatch) ||
95 IsEqualIID(riid, &IID_IUnknown))
96 {
97 *obj = iface;
98 ITextStream_AddRef(iface);
99 return S_OK;
100 }
101
102 *obj = NULL;
103 return E_NOINTERFACE;
104 }
105
106 static ULONG WINAPI textstream_AddRef(ITextStream *iface)
107 {
108 struct textstream *This = impl_from_ITextStream(iface);
109 ULONG ref = InterlockedIncrement(&This->ref);
110 TRACE("(%p)->(%d)\n", This, ref);
111 return ref;
112 }
113
114 static ULONG WINAPI textstream_Release(ITextStream *iface)
115 {
116 struct textstream *This = impl_from_ITextStream(iface);
117 ULONG ref = InterlockedDecrement(&This->ref);
118 TRACE("(%p)->(%d)\n", This, ref);
119
120 if (!ref)
121 heap_free(This);
122
123 return ref;
124 }
125
126 static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
127 {
128 struct textstream *This = impl_from_ITextStream(iface);
129 TRACE("(%p)->(%p)\n", This, pctinfo);
130 *pctinfo = 1;
131 return S_OK;
132 }
133
134 static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
135 LCID lcid, ITypeInfo **ppTInfo)
136 {
137 struct textstream *This = impl_from_ITextStream(iface);
138 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
139 return get_typeinfo(ITextStream_tid, ppTInfo);
140 }
141
142 static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
143 LPOLESTR *rgszNames, UINT cNames,
144 LCID lcid, DISPID *rgDispId)
145 {
146 struct textstream *This = impl_from_ITextStream(iface);
147 ITypeInfo *typeinfo;
148 HRESULT hr;
149
150 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
151
152 hr = get_typeinfo(ITextStream_tid, &typeinfo);
153 if(SUCCEEDED(hr))
154 {
155 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
156 ITypeInfo_Release(typeinfo);
157 }
158
159 return hr;
160 }
161
162 static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
163 REFIID riid, LCID lcid, WORD wFlags,
164 DISPPARAMS *pDispParams, VARIANT *pVarResult,
165 EXCEPINFO *pExcepInfo, UINT *puArgErr)
166 {
167 struct textstream *This = impl_from_ITextStream(iface);
168 ITypeInfo *typeinfo;
169 HRESULT hr;
170
171 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
172 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
173
174 hr = get_typeinfo(ITextStream_tid, &typeinfo);
175 if(SUCCEEDED(hr))
176 {
177 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
178 pDispParams, pVarResult, pExcepInfo, puArgErr);
179 ITypeInfo_Release(typeinfo);
180 }
181
182 return hr;
183 }
184
185 static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
186 {
187 struct textstream *This = impl_from_ITextStream(iface);
188 FIXME("(%p)->(%p): stub\n", This, line);
189 return E_NOTIMPL;
190 }
191
192 static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
193 {
194 struct textstream *This = impl_from_ITextStream(iface);
195 FIXME("(%p)->(%p): stub\n", This, column);
196 return E_NOTIMPL;
197 }
198
199 static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
200 {
201 struct textstream *This = impl_from_ITextStream(iface);
202 FIXME("(%p)->(%p): stub\n", This, eos);
203 return E_NOTIMPL;
204 }
205
206 static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
207 {
208 struct textstream *This = impl_from_ITextStream(iface);
209 FIXME("(%p)->(%p): stub\n", This, eol);
210 return E_NOTIMPL;
211 }
212
213 static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
214 {
215 struct textstream *This = impl_from_ITextStream(iface);
216 FIXME("(%p)->(%p): stub\n", This, text);
217
218 if (textstream_check_iomode(This, IORead))
219 return CTL_E_BADFILEMODE;
220
221 return E_NOTIMPL;
222 }
223
224 static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
225 {
226 struct textstream *This = impl_from_ITextStream(iface);
227 FIXME("(%p)->(%p): stub\n", This, text);
228
229 if (textstream_check_iomode(This, IORead))
230 return CTL_E_BADFILEMODE;
231
232 return E_NOTIMPL;
233 }
234
235 static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
236 {
237 struct textstream *This = impl_from_ITextStream(iface);
238 FIXME("(%p)->(%p): stub\n", This, text);
239
240 if (textstream_check_iomode(This, IORead))
241 return CTL_E_BADFILEMODE;
242
243 return E_NOTIMPL;
244 }
245
246 static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
247 {
248 struct textstream *This = impl_from_ITextStream(iface);
249 FIXME("(%p)->(%s): stub\n", This, debugstr_w(text));
250 return E_NOTIMPL;
251 }
252
253 static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
254 {
255 struct textstream *This = impl_from_ITextStream(iface);
256 FIXME("(%p)->(%s): stub\n", This, debugstr_w(text));
257 return E_NOTIMPL;
258 }
259
260 static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
261 {
262 struct textstream *This = impl_from_ITextStream(iface);
263 FIXME("(%p)->(%d): stub\n", This, lines);
264 return E_NOTIMPL;
265 }
266
267 static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
268 {
269 struct textstream *This = impl_from_ITextStream(iface);
270 FIXME("(%p)->(%d): stub\n", This, count);
271 return E_NOTIMPL;
272 }
273
274 static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
275 {
276 struct textstream *This = impl_from_ITextStream(iface);
277 FIXME("(%p): stub\n", This);
278 return E_NOTIMPL;
279 }
280
281 static HRESULT WINAPI textstream_Close(ITextStream *iface)
282 {
283 struct textstream *This = impl_from_ITextStream(iface);
284 FIXME("(%p): stub\n", This);
285 return E_NOTIMPL;
286 }
287
288 static const ITextStreamVtbl textstreamvtbl = {
289 textstream_QueryInterface,
290 textstream_AddRef,
291 textstream_Release,
292 textstream_GetTypeInfoCount,
293 textstream_GetTypeInfo,
294 textstream_GetIDsOfNames,
295 textstream_Invoke,
296 textstream_get_Line,
297 textstream_get_Column,
298 textstream_get_AtEndOfStream,
299 textstream_get_AtEndOfLine,
300 textstream_Read,
301 textstream_ReadLine,
302 textstream_ReadAll,
303 textstream_Write,
304 textstream_WriteLine,
305 textstream_WriteBlankLines,
306 textstream_Skip,
307 textstream_SkipLine,
308 textstream_Close
309 };
310
311 static HRESULT create_textstream(IOMode mode, ITextStream **ret)
312 {
313 struct textstream *stream;
314
315 stream = heap_alloc(sizeof(struct textstream));
316 if (!stream) return E_OUTOFMEMORY;
317
318 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
319 stream->ref = 1;
320 stream->mode = mode;
321
322 *ret = &stream->ITextStream_iface;
323 return S_OK;
324 }
325
326 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
327 {
328 struct folder *This = impl_from_IFolder(iface);
329
330 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
331
332 *obj = NULL;
333
334 if (IsEqualGUID( riid, &IID_IFolder ) ||
335 IsEqualGUID( riid, &IID_IUnknown))
336 {
337 *obj = iface;
338 IFolder_AddRef(iface);
339 }
340 else
341 return E_NOINTERFACE;
342
343 return S_OK;
344 }
345
346 static ULONG WINAPI folder_AddRef(IFolder *iface)
347 {
348 struct folder *This = impl_from_IFolder(iface);
349 ULONG ref = InterlockedIncrement(&This->ref);
350 TRACE("(%p)->(%d)\n", This, ref);
351 return ref;
352 }
353
354 static ULONG WINAPI folder_Release(IFolder *iface)
355 {
356 struct folder *This = impl_from_IFolder(iface);
357 ULONG ref = InterlockedDecrement(&This->ref);
358 TRACE("(%p)->(%d)\n", This, ref);
359
360 if (!ref)
361 heap_free(This);
362
363 return ref;
364 }
365
366 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
367 {
368 struct folder *This = impl_from_IFolder(iface);
369 TRACE("(%p)->(%p)\n", This, pctinfo);
370 *pctinfo = 1;
371 return S_OK;
372 }
373
374 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
375 LCID lcid, ITypeInfo **ppTInfo)
376 {
377 struct folder *This = impl_from_IFolder(iface);
378 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
379 return get_typeinfo(IFolder_tid, ppTInfo);
380 }
381
382 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
383 LPOLESTR *rgszNames, UINT cNames,
384 LCID lcid, DISPID *rgDispId)
385 {
386 struct folder *This = impl_from_IFolder(iface);
387 ITypeInfo *typeinfo;
388 HRESULT hr;
389
390 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
391
392 hr = get_typeinfo(IFolder_tid, &typeinfo);
393 if(SUCCEEDED(hr))
394 {
395 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
396 ITypeInfo_Release(typeinfo);
397 }
398
399 return hr;
400 }
401
402 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
403 REFIID riid, LCID lcid, WORD wFlags,
404 DISPPARAMS *pDispParams, VARIANT *pVarResult,
405 EXCEPINFO *pExcepInfo, UINT *puArgErr)
406 {
407 struct folder *This = impl_from_IFolder(iface);
408 ITypeInfo *typeinfo;
409 HRESULT hr;
410
411 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
412 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
413
414 hr = get_typeinfo(IFolder_tid, &typeinfo);
415 if(SUCCEEDED(hr))
416 {
417 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
418 pDispParams, pVarResult, pExcepInfo, puArgErr);
419 ITypeInfo_Release(typeinfo);
420 }
421
422 return hr;
423 }
424
425 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
426 {
427 struct folder *This = impl_from_IFolder(iface);
428 FIXME("(%p)->(%p): stub\n", This, path);
429 return E_NOTIMPL;
430 }
431
432 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
433 {
434 struct folder *This = impl_from_IFolder(iface);
435 FIXME("(%p)->(%p): stub\n", This, name);
436 return E_NOTIMPL;
437 }
438
439 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
440 {
441 struct folder *This = impl_from_IFolder(iface);
442 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
443 return E_NOTIMPL;
444 }
445
446 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
447 {
448 struct folder *This = impl_from_IFolder(iface);
449 FIXME("(%p)->(%p): stub\n", This, path);
450 return E_NOTIMPL;
451 }
452
453 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
454 {
455 struct folder *This = impl_from_IFolder(iface);
456 FIXME("(%p)->(%p): stub\n", This, name);
457 return E_NOTIMPL;
458 }
459
460 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
461 {
462 struct folder *This = impl_from_IFolder(iface);
463 FIXME("(%p)->(%p): stub\n", This, drive);
464 return E_NOTIMPL;
465 }
466
467 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
468 {
469 struct folder *This = impl_from_IFolder(iface);
470 FIXME("(%p)->(%p): stub\n", This, parent);
471 return E_NOTIMPL;
472 }
473
474 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
475 {
476 struct folder *This = impl_from_IFolder(iface);
477 FIXME("(%p)->(%p): stub\n", This, attr);
478 return E_NOTIMPL;
479 }
480
481 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
482 {
483 struct folder *This = impl_from_IFolder(iface);
484 FIXME("(%p)->(0x%x): stub\n", This, attr);
485 return E_NOTIMPL;
486 }
487
488 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
489 {
490 struct folder *This = impl_from_IFolder(iface);
491 FIXME("(%p)->(%p): stub\n", This, date);
492 return E_NOTIMPL;
493 }
494
495 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
496 {
497 struct folder *This = impl_from_IFolder(iface);
498 FIXME("(%p)->(%p): stub\n", This, date);
499 return E_NOTIMPL;
500 }
501
502 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
503 {
504 struct folder *This = impl_from_IFolder(iface);
505 FIXME("(%p)->(%p): stub\n", This, date);
506 return E_NOTIMPL;
507 }
508
509 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
510 {
511 struct folder *This = impl_from_IFolder(iface);
512 FIXME("(%p)->(%p): stub\n", This, type);
513 return E_NOTIMPL;
514 }
515
516 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
517 {
518 struct folder *This = impl_from_IFolder(iface);
519 FIXME("(%p)->(%x): stub\n", This, force);
520 return E_NOTIMPL;
521 }
522
523 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
524 {
525 struct folder *This = impl_from_IFolder(iface);
526 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
527 return E_NOTIMPL;
528 }
529
530 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
531 {
532 struct folder *This = impl_from_IFolder(iface);
533 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
534 return E_NOTIMPL;
535 }
536
537 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
538 {
539 struct folder *This = impl_from_IFolder(iface);
540 FIXME("(%p)->(%p): stub\n", This, isroot);
541 return E_NOTIMPL;
542 }
543
544 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
545 {
546 struct folder *This = impl_from_IFolder(iface);
547 FIXME("(%p)->(%p): stub\n", This, size);
548 return E_NOTIMPL;
549 }
550
551 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
552 {
553 struct folder *This = impl_from_IFolder(iface);
554 FIXME("(%p)->(%p): stub\n", This, folders);
555 return E_NOTIMPL;
556 }
557
558 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
559 {
560 struct folder *This = impl_from_IFolder(iface);
561 FIXME("(%p)->(%p): stub\n", This, files);
562 return E_NOTIMPL;
563 }
564
565 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
566 VARIANT_BOOL unicode, ITextStream **stream)
567 {
568 struct folder *This = impl_from_IFolder(iface);
569 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
570 return E_NOTIMPL;
571 }
572
573 static const IFolderVtbl foldervtbl = {
574 folder_QueryInterface,
575 folder_AddRef,
576 folder_Release,
577 folder_GetTypeInfoCount,
578 folder_GetTypeInfo,
579 folder_GetIDsOfNames,
580 folder_Invoke,
581 folder_get_Path,
582 folder_get_Name,
583 folder_put_Name,
584 folder_get_ShortPath,
585 folder_get_ShortName,
586 folder_get_Drive,
587 folder_get_ParentFolder,
588 folder_get_Attributes,
589 folder_put_Attributes,
590 folder_get_DateCreated,
591 folder_get_DateLastModified,
592 folder_get_DateLastAccessed,
593 folder_get_Type,
594 folder_Delete,
595 folder_Copy,
596 folder_Move,
597 folder_get_IsRootFolder,
598 folder_get_Size,
599 folder_get_SubFolders,
600 folder_get_Files,
601 folder_CreateTextFile
602 };
603
604 static HRESULT create_folder(IFolder **folder)
605 {
606 struct folder *This;
607
608 This = heap_alloc(sizeof(struct folder));
609 if (!This) return E_OUTOFMEMORY;
610
611 This->IFolder_iface.lpVtbl = &foldervtbl;
612 This->ref = 1;
613
614 *folder = &This->IFolder_iface;
615
616 return S_OK;
617 }
618
619 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
620 {
621 struct file *This = impl_from_IFile(iface);
622
623 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
624
625 if (IsEqualIID(riid, &IID_IFile) ||
626 IsEqualIID(riid, &IID_IDispatch) ||
627 IsEqualIID(riid, &IID_IUnknown))
628 {
629 *obj = iface;
630 IFile_AddRef(iface);
631 return S_OK;
632 }
633
634 *obj = NULL;
635 return E_NOINTERFACE;
636 }
637
638 static ULONG WINAPI file_AddRef(IFile *iface)
639 {
640 struct file *This = impl_from_IFile(iface);
641 LONG ref = InterlockedIncrement(&This->ref);
642
643 TRACE("(%p) ref=%d\n", This, ref);
644
645 return ref;
646 }
647
648 static ULONG WINAPI file_Release(IFile *iface)
649 {
650 struct file *This = impl_from_IFile(iface);
651 LONG ref = InterlockedDecrement(&This->ref);
652
653 TRACE("(%p) ref=%d\n", This, ref);
654
655 if(!ref)
656 heap_free(This->path);
657
658 return ref;
659 }
660
661 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
662 {
663 struct file *This = impl_from_IFile(iface);
664
665 TRACE("(%p)->(%p)\n", This, pctinfo);
666
667 *pctinfo = 1;
668 return S_OK;
669 }
670
671 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
672 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
673 {
674 struct file *This = impl_from_IFile(iface);
675
676 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
677
678 return get_typeinfo(IFile_tid, ppTInfo);
679 }
680
681 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
682 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
683 {
684 struct file *This = impl_from_IFile(iface);
685 ITypeInfo *typeinfo;
686 HRESULT hr;
687
688 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
689 rgszNames, cNames, lcid, rgDispId);
690
691 hr = get_typeinfo(IFile_tid, &typeinfo);
692 if(SUCCEEDED(hr)) {
693 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
694 ITypeInfo_Release(typeinfo);
695 }
696 return hr;
697 }
698
699 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
700 {
701 struct file *This = impl_from_IFile(iface);
702 ITypeInfo *typeinfo;
703 HRESULT hr;
704
705 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
706 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
707
708 hr = get_typeinfo(IFile_tid, &typeinfo);
709 if(SUCCEEDED(hr))
710 {
711 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
712 pDispParams, pVarResult, pExcepInfo, puArgErr);
713 ITypeInfo_Release(typeinfo);
714 }
715 return hr;
716 }
717
718 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *pbstrPath)
719 {
720 struct file *This = impl_from_IFile(iface);
721 FIXME("(%p)->(%p)\n", This, pbstrPath);
722 return E_NOTIMPL;
723 }
724
725 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *pbstrName)
726 {
727 struct file *This = impl_from_IFile(iface);
728 FIXME("(%p)->(%p)\n", This, pbstrName);
729 return E_NOTIMPL;
730 }
731
732 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
733 {
734 struct file *This = impl_from_IFile(iface);
735 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
736 return E_NOTIMPL;
737 }
738
739 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
740 {
741 struct file *This = impl_from_IFile(iface);
742 FIXME("(%p)->(%p)\n", This, pbstrPath);
743 return E_NOTIMPL;
744 }
745
746 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
747 {
748 struct file *This = impl_from_IFile(iface);
749 FIXME("(%p)->(%p)\n", This, pbstrName);
750 return E_NOTIMPL;
751 }
752
753 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
754 {
755 struct file *This = impl_from_IFile(iface);
756 FIXME("(%p)->(%p)\n", This, ppdrive);
757 return E_NOTIMPL;
758 }
759
760 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
761 {
762 struct file *This = impl_from_IFile(iface);
763 FIXME("(%p)->(%p)\n", This, ppfolder);
764 return E_NOTIMPL;
765 }
766
767 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
768 {
769 struct file *This = impl_from_IFile(iface);
770 DWORD fa;
771
772 TRACE("(%p)->(%p)\n", This, pfa);
773
774 if(!pfa)
775 return E_POINTER;
776
777 fa = GetFileAttributesW(This->path);
778 if(fa == INVALID_FILE_ATTRIBUTES)
779 return create_error(GetLastError());
780
781 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
782 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
783 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
784 return S_OK;
785 }
786
787 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
788 {
789 struct file *This = impl_from_IFile(iface);
790 FIXME("(%p)->(%x)\n", This, pfa);
791 return E_NOTIMPL;
792 }
793
794 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
795 {
796 struct file *This = impl_from_IFile(iface);
797 FIXME("(%p)->(%p)\n", This, pdate);
798 return E_NOTIMPL;
799 }
800
801 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *pdate)
802 {
803 struct file *This = impl_from_IFile(iface);
804 FIXME("(%p)->(%p)\n", This, pdate);
805 return E_NOTIMPL;
806 }
807
808 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
809 {
810 struct file *This = impl_from_IFile(iface);
811 FIXME("(%p)->(%p)\n", This, pdate);
812 return E_NOTIMPL;
813 }
814
815 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
816 {
817 struct file *This = impl_from_IFile(iface);
818 WIN32_FIND_DATAW fd;
819 HANDLE f;
820
821 TRACE("(%p)->(%p)\n", This, pvarSize);
822
823 if(!pvarSize)
824 return E_POINTER;
825
826 f = FindFirstFileW(This->path, &fd);
827 if(f == INVALID_HANDLE_VALUE)
828 return create_error(GetLastError());
829 FindClose(f);
830
831 if(fd.nFileSizeHigh || fd.nFileSizeLow>INT_MAX) {
832 V_VT(pvarSize) = VT_R8;
833 V_R8(pvarSize) = ((ULONGLONG)fd.nFileSizeHigh<<32) + fd.nFileSizeLow;
834 }else {
835 V_VT(pvarSize) = VT_I4;
836 V_I4(pvarSize) = fd.nFileSizeLow;
837 }
838 return S_OK;
839 }
840
841 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
842 {
843 struct file *This = impl_from_IFile(iface);
844 FIXME("(%p)->(%p)\n", This, pbstrType);
845 return E_NOTIMPL;
846 }
847
848 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
849 {
850 struct file *This = impl_from_IFile(iface);
851 FIXME("(%p)->(%x)\n", This, Force);
852 return E_NOTIMPL;
853 }
854
855 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
856 {
857 struct file *This = impl_from_IFile(iface);
858 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
859 return E_NOTIMPL;
860 }
861
862 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
863 {
864 struct file *This = impl_from_IFile(iface);
865 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
866 return E_NOTIMPL;
867 }
868
869 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode IOMode, Tristate Format, ITextStream **ppts)
870 {
871 struct file *This = impl_from_IFile(iface);
872 FIXME("(%p)->(%x %x %p)\n", This, IOMode, Format, ppts);
873 return E_NOTIMPL;
874 }
875
876 static const IFileVtbl file_vtbl = {
877 file_QueryInterface,
878 file_AddRef,
879 file_Release,
880 file_GetTypeInfoCount,
881 file_GetTypeInfo,
882 file_GetIDsOfNames,
883 file_Invoke,
884 file_get_Path,
885 file_get_Name,
886 file_put_Name,
887 file_get_ShortPath,
888 file_get_ShortName,
889 file_get_Drive,
890 file_get_ParentFolder,
891 file_get_Attributes,
892 file_put_Attributes,
893 file_get_DateCreated,
894 file_get_DateLastModified,
895 file_get_DateLastAccessed,
896 file_get_Size,
897 file_get_Type,
898 file_Delete,
899 file_Copy,
900 file_Move,
901 file_OpenAsTextStream
902 };
903
904 static HRESULT create_file(BSTR path, IFile **file)
905 {
906 struct file *f;
907 DWORD len, attrs;
908
909 *file = NULL;
910
911 f = heap_alloc(sizeof(struct file));
912 if(!f)
913 return E_OUTOFMEMORY;
914
915 f->IFile_iface.lpVtbl = &file_vtbl;
916 f->ref = 1;
917
918 len = GetFullPathNameW(path, 0, NULL, NULL);
919 if(!len) {
920 heap_free(f);
921 return E_FAIL;
922 }
923
924 f->path = heap_alloc(len*sizeof(WCHAR));
925 if(!f->path) {
926 heap_free(f);
927 return E_OUTOFMEMORY;
928 }
929
930 if(!GetFullPathNameW(path, len, f->path, NULL)) {
931 heap_free(f->path);
932 heap_free(f);
933 return E_FAIL;
934 }
935
936 if(path[len-1]=='/' || path[len-1]=='\\')
937 path[len-1] = 0;
938
939 attrs = GetFileAttributesW(f->path);
940 if(attrs==INVALID_FILE_ATTRIBUTES ||
941 (attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
942 heap_free(f->path);
943 heap_free(f);
944 return create_error(GetLastError());
945 }
946
947 *file = &f->IFile_iface;
948 return S_OK;
949 }
950
951 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
952 {
953 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
954
955 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
956 IsEqualGUID( riid, &IID_IFileSystem ) ||
957 IsEqualGUID( riid, &IID_IDispatch ) ||
958 IsEqualGUID( riid, &IID_IUnknown ) )
959 {
960 *ppvObject = iface;
961 }
962 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
963 {
964 TRACE("Interface IDispatchEx not supported - returning NULL\n");
965 *ppvObject = NULL;
966 return E_NOINTERFACE;
967 }
968 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
969 {
970 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
971 *ppvObject = NULL;
972 return E_NOINTERFACE;
973 }
974 else
975 {
976 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
977 return E_NOINTERFACE;
978 }
979
980 IFileSystem3_AddRef(iface);
981
982 return S_OK;
983 }
984
985 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
986 {
987 TRACE("%p\n", iface);
988
989 return 2;
990 }
991
992 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
993 {
994 TRACE("%p\n", iface);
995
996 return 1;
997 }
998
999 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
1000 {
1001 TRACE("(%p)->(%p)\n", iface, pctinfo);
1002
1003 *pctinfo = 1;
1004 return S_OK;
1005 }
1006
1007 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
1008 LCID lcid, ITypeInfo **ppTInfo)
1009 {
1010 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
1011 return get_typeinfo(IFileSystem3_tid, ppTInfo);
1012 }
1013
1014 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
1015 LPOLESTR *rgszNames, UINT cNames,
1016 LCID lcid, DISPID *rgDispId)
1017 {
1018 ITypeInfo *typeinfo;
1019 HRESULT hr;
1020
1021 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1022
1023 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
1024 if(SUCCEEDED(hr))
1025 {
1026 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1027 ITypeInfo_Release(typeinfo);
1028 }
1029
1030 return hr;
1031 }
1032
1033 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
1034 REFIID riid, LCID lcid, WORD wFlags,
1035 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1036 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1037 {
1038 ITypeInfo *typeinfo;
1039 HRESULT hr;
1040
1041 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
1042 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1043
1044 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
1045 if(SUCCEEDED(hr))
1046 {
1047 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1048 pDispParams, pVarResult, pExcepInfo, puArgErr);
1049 ITypeInfo_Release(typeinfo);
1050 }
1051
1052 return hr;
1053 }
1054
1055 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
1056 {
1057 FIXME("%p %p\n", iface, ppdrives);
1058
1059 return E_NOTIMPL;
1060 }
1061
1062 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
1063 BSTR Name, BSTR *pbstrResult)
1064 {
1065 FIXME("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), pbstrResult);
1066
1067 return E_NOTIMPL;
1068 }
1069
1070 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR Path,
1071 BSTR *pbstrResult)
1072 {
1073 FIXME("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
1074
1075 return E_NOTIMPL;
1076 }
1077
1078 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
1079 {
1080 int i;
1081
1082 if(!path)
1083 return 0;
1084
1085 for(i=len-1; i>=0; i--)
1086 if(path[i]!='/' && path[i]!='\\')
1087 break;
1088
1089 for(; i>=0; i--)
1090 if(path[i]=='/' || path[i]=='\\')
1091 break;
1092
1093 for(; i>=0; i--)
1094 if(path[i]!='/' && path[i]!='\\')
1095 break;
1096
1097 if(i < 0)
1098 return 0;
1099
1100 if(path[i]==':' && i==1)
1101 i++;
1102 return i+1;
1103 }
1104
1105 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
1106 BSTR *pbstrResult)
1107 {
1108 DWORD len;
1109
1110 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
1111
1112 if(!pbstrResult)
1113 return E_POINTER;
1114
1115 len = get_parent_folder_name(Path, SysStringLen(Path));
1116 if(!len) {
1117 *pbstrResult = NULL;
1118 return S_OK;
1119 }
1120
1121 *pbstrResult = SysAllocStringLen(Path, len);
1122 if(!*pbstrResult)
1123 return E_OUTOFMEMORY;
1124 return S_OK;
1125 }
1126
1127 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
1128 BSTR *pbstrResult)
1129 {
1130 int i, end;
1131
1132 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
1133
1134 if(!pbstrResult)
1135 return E_POINTER;
1136
1137 if(!Path) {
1138 *pbstrResult = NULL;
1139 return S_OK;
1140 }
1141
1142 for(end=strlenW(Path)-1; end>=0; end--)
1143 if(Path[end]!='/' && Path[end]!='\\')
1144 break;
1145
1146 for(i=end; i>=0; i--)
1147 if(Path[i]=='/' || Path[i]=='\\')
1148 break;
1149 i++;
1150
1151 if(i>end || (i==0 && end==1 && Path[1]==':')) {
1152 *pbstrResult = NULL;
1153 return S_OK;
1154 }
1155
1156 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
1157 if(!*pbstrResult)
1158 return E_OUTOFMEMORY;
1159 return S_OK;
1160 }
1161
1162 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
1163 BSTR *pbstrResult)
1164 {
1165 int i, end;
1166
1167 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
1168
1169 if(!pbstrResult)
1170 return E_POINTER;
1171
1172 if(!Path) {
1173 *pbstrResult = NULL;
1174 return S_OK;
1175 }
1176
1177 for(end=strlenW(Path)-1; end>=0; end--)
1178 if(Path[end]!='/' && Path[end]!='\\')
1179 break;
1180
1181 for(i=end; i>=0; i--) {
1182 if(Path[i]=='.' && Path[end+1]!='.')
1183 end = i-1;
1184 if(Path[i]=='/' || Path[i]=='\\')
1185 break;
1186 }
1187 i++;
1188
1189 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
1190 *pbstrResult = NULL;
1191 return S_OK;
1192 }
1193
1194 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
1195 if(!*pbstrResult)
1196 return E_OUTOFMEMORY;
1197 return S_OK;
1198 }
1199
1200 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR Path,
1201 BSTR *pbstrResult)
1202 {
1203 FIXME("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
1204
1205 return E_NOTIMPL;
1206 }
1207
1208 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
1209 BSTR *pbstrResult)
1210 {
1211 static const WCHAR cur_path[] = {'.',0};
1212
1213 WCHAR buf[MAX_PATH], ch;
1214 const WCHAR *path;
1215 DWORD i, beg, len, exp_len;
1216 WIN32_FIND_DATAW fdata;
1217 HANDLE fh;
1218
1219 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
1220
1221 if(!pbstrResult)
1222 return E_POINTER;
1223
1224 if(!Path)
1225 path = cur_path;
1226 else
1227 path = Path;
1228
1229 len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
1230 if(!len)
1231 return E_FAIL;
1232
1233 buf[0] = toupperW(buf[0]);
1234 if(len>3 && buf[len-1] == '\\')
1235 buf[--len] = 0;
1236
1237 for(beg=3, i=3; i<=len; i++) {
1238 if(buf[i]!='\\' && buf[i])
1239 continue;
1240
1241 ch = buf[i];
1242 buf[i] = 0;
1243 fh = FindFirstFileW(buf, &fdata);
1244 if(fh == INVALID_HANDLE_VALUE)
1245 break;
1246
1247 exp_len = strlenW(fdata.cFileName);
1248 if(exp_len == i-beg)
1249 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
1250 FindClose(fh);
1251 buf[i] = ch;
1252 beg = i+1;
1253 }
1254
1255 *pbstrResult = SysAllocString(buf);
1256 if(!*pbstrResult)
1257 return E_OUTOFMEMORY;
1258 return S_OK;
1259 }
1260
1261 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
1262 {
1263 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
1264
1265 DWORD random;
1266
1267 TRACE("%p %p\n", iface, pbstrResult);
1268
1269 if(!pbstrResult)
1270 return E_POINTER;
1271
1272 *pbstrResult = SysAllocStringLen(NULL, 12);
1273 if(!*pbstrResult)
1274 return E_OUTOFMEMORY;
1275
1276 if(!RtlGenRandom(&random, sizeof(random)))
1277 return E_FAIL;
1278 sprintfW(*pbstrResult, fmt, random & 0xfffff);
1279 return S_OK;
1280 }
1281
1282 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
1283 VARIANT_BOOL *pfExists)
1284 {
1285 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
1286
1287 return E_NOTIMPL;
1288 }
1289
1290 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
1291 {
1292 DWORD attrs;
1293 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
1294
1295 if (!ret) return E_POINTER;
1296
1297 attrs = GetFileAttributesW(path);
1298 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
1299 return S_OK;
1300 }
1301
1302 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
1303 {
1304 DWORD attrs;
1305 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
1306
1307 if (!ret) return E_POINTER;
1308
1309 attrs = GetFileAttributesW(path);
1310 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
1311
1312 return S_OK;
1313 }
1314
1315 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
1316 IDrive **ppdrive)
1317 {
1318 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
1319
1320 return E_NOTIMPL;
1321 }
1322
1323 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
1324 IFile **ppfile)
1325 {
1326 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
1327
1328 if(!ppfile)
1329 return E_POINTER;
1330 if(!FilePath)
1331 return E_INVALIDARG;
1332
1333 return create_file(FilePath, ppfile);
1334 }
1335
1336 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
1337 IFolder **ppfolder)
1338 {
1339 FIXME("%p %s %p\n", iface, debugstr_w(FolderPath), ppfolder);
1340
1341 return E_NOTIMPL;
1342 }
1343
1344 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
1345 SpecialFolderConst SpecialFolder,
1346 IFolder **ppfolder)
1347 {
1348 FIXME("%p %d %p\n", iface, SpecialFolder, ppfolder);
1349
1350 return E_NOTIMPL;
1351 }
1352
1353 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
1354 {
1355 WCHAR path[MAX_PATH];
1356 DWORD len, name_len;
1357 WIN32_FIND_DATAW ffd;
1358 HANDLE f;
1359
1360 f = FindFirstFileW(file, &ffd);
1361 if(f == INVALID_HANDLE_VALUE)
1362 return create_error(GetLastError());
1363
1364 len = get_parent_folder_name(file, file_len);
1365 if(len+1 >= MAX_PATH) {
1366 FindClose(f);
1367 return E_FAIL;
1368 }
1369 if(len) {
1370 memcpy(path, file, len*sizeof(WCHAR));
1371 path[len++] = '\\';
1372 }
1373
1374 do {
1375 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
1376 continue;
1377
1378 name_len = strlenW(ffd.cFileName);
1379 if(len+name_len+1 >= MAX_PATH) {
1380 FindClose(f);
1381 return E_FAIL;
1382 }
1383 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
1384
1385 TRACE("deleting %s\n", debugstr_w(path));
1386
1387 if(!DeleteFileW(path)) {
1388 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
1389 || !DeleteFileW(path)) {
1390 FindClose(f);
1391 return create_error(GetLastError());
1392 }
1393 }
1394 } while(FindNextFileW(f, &ffd));
1395 FindClose(f);
1396
1397 return S_OK;
1398 }
1399
1400 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
1401 VARIANT_BOOL Force)
1402 {
1403 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
1404
1405 if(!FileSpec)
1406 return E_POINTER;
1407
1408 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
1409 }
1410
1411 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
1412 {
1413 WCHAR path[MAX_PATH];
1414 DWORD len, name_len;
1415 WIN32_FIND_DATAW ffd;
1416 HANDLE f;
1417 HRESULT hr;
1418
1419 f = FindFirstFileW(folder, &ffd);
1420 if(f == INVALID_HANDLE_VALUE)
1421 return create_error(GetLastError());
1422
1423 len = get_parent_folder_name(folder, folder_len);
1424 if(len+1 >= MAX_PATH) {
1425 FindClose(f);
1426 return E_FAIL;
1427 }
1428 if(len) {
1429 memcpy(path, folder, len*sizeof(WCHAR));
1430 path[len++] = '\\';
1431 }
1432
1433 do {
1434 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1435 continue;
1436 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
1437 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
1438 continue;
1439
1440 name_len = strlenW(ffd.cFileName);
1441 if(len+name_len+3 >= MAX_PATH) {
1442 FindClose(f);
1443 return E_FAIL;
1444 }
1445 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
1446 path[len+name_len] = '\\';
1447 path[len+name_len+1] = '*';
1448 path[len+name_len+2] = 0;
1449
1450 hr = delete_file(path, len+name_len+2, force);
1451 if(FAILED(hr)) {
1452 FindClose(f);
1453 return hr;
1454 }
1455
1456 hr = delete_folder(path, len+name_len+2, force);
1457 if(FAILED(hr)) {
1458 FindClose(f);
1459 return hr;
1460 }
1461
1462 path[len+name_len] = 0;
1463 TRACE("deleting %s\n", debugstr_w(path));
1464
1465 if(!RemoveDirectoryW(path)) {
1466 FindClose(f);
1467 return create_error(GetLastError());
1468 }
1469 } while(FindNextFileW(f, &ffd));
1470 FindClose(f);
1471
1472 return S_OK;
1473 }
1474
1475 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
1476 VARIANT_BOOL Force)
1477 {
1478 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
1479
1480 if(!FolderSpec)
1481 return E_POINTER;
1482
1483 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
1484 }
1485
1486 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
1487 BSTR Destination)
1488 {
1489 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
1490
1491 return E_NOTIMPL;
1492 }
1493
1494 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
1495 BSTR Destination)
1496 {
1497 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
1498
1499 return E_NOTIMPL;
1500 }
1501
1502 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
1503 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
1504 {
1505 DWORD attrs;
1506 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
1507 DWORD src_len, dst_len, name_len;
1508 WIN32_FIND_DATAW ffd;
1509 HANDLE f;
1510 HRESULT hr;
1511
1512 if(!source[0] || !destination[0])
1513 return E_INVALIDARG;
1514
1515 attrs = GetFileAttributesW(destination);
1516 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
1517 attrs = GetFileAttributesW(source);
1518 if(attrs == INVALID_FILE_ATTRIBUTES)
1519 return create_error(GetLastError());
1520 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
1521 return CTL_E_FILENOTFOUND;
1522
1523 if(!CopyFileW(source, destination, !overwrite))
1524 return create_error(GetLastError());
1525 return S_OK;
1526 }
1527
1528 f = FindFirstFileW(source, &ffd);
1529 if(f == INVALID_HANDLE_VALUE)
1530 return CTL_E_FILENOTFOUND;
1531
1532 src_len = get_parent_folder_name(source, source_len);
1533 if(src_len+1 >= MAX_PATH)
1534 return E_FAIL;
1535 if(src_len) {
1536 memcpy(src_path, source, src_len*sizeof(WCHAR));
1537 src_path[src_len++] = '\\';
1538 }
1539
1540 dst_len = destination_len;
1541 if(dst_len+1 >= MAX_PATH) {
1542 FindClose(f);
1543 return E_FAIL;
1544 }
1545 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
1546 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
1547 dst_path[dst_len++] = '\\';
1548
1549 hr = CTL_E_FILENOTFOUND;
1550 do {
1551 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
1552 continue;
1553
1554 name_len = strlenW(ffd.cFileName);
1555 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
1556 FindClose(f);
1557 return E_FAIL;
1558 }
1559 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
1560 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
1561
1562 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
1563
1564 if(!CopyFileW(src_path, dst_path, !overwrite)) {
1565 FindClose(f);
1566 return create_error(GetLastError());
1567 }else {
1568 hr = S_OK;
1569 }
1570 } while(FindNextFileW(f, &ffd));
1571 FindClose(f);
1572
1573 return hr;
1574 }
1575
1576 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
1577 BSTR Destination, VARIANT_BOOL OverWriteFiles)
1578 {
1579 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
1580
1581 if(!Source || !Destination)
1582 return E_POINTER;
1583
1584 return copy_file(Source, SysStringLen(Source), Destination,
1585 SysStringLen(Destination), OverWriteFiles);
1586 }
1587
1588 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
1589 DWORD destination_len, VARIANT_BOOL overwrite)
1590 {
1591 DWORD tmp, src_len, dst_len, name_len;
1592 WCHAR src[MAX_PATH], dst[MAX_PATH];
1593 WIN32_FIND_DATAW ffd;
1594 HANDLE f;
1595 HRESULT hr;
1596 BOOL copied = FALSE;
1597
1598 if(!source[0] || !destination[0])
1599 return E_INVALIDARG;
1600
1601 dst_len = destination_len;
1602 if(dst_len+1 >= MAX_PATH)
1603 return E_FAIL;
1604 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
1605
1606 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
1607 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
1608 tmp&FILE_ATTRIBUTE_DIRECTORY) {
1609 if(!CreateDirectoryW(dst, NULL)) {
1610 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
1611 tmp = GetFileAttributesW(dst);
1612 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
1613 return CTL_E_FILEALREADYEXISTS;
1614 }else {
1615 return create_error(GetLastError());
1616 }
1617 }
1618 copied = TRUE;
1619
1620 src_len = source_len;
1621 if(src_len+2 >= MAX_PATH)
1622 return E_FAIL;
1623 memcpy(src, source, src_len*sizeof(WCHAR));
1624 src[src_len++] = '\\';
1625 src[src_len] = '*';
1626 src[src_len+1] = 0;
1627
1628 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
1629 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
1630 return create_error(GetLastError());
1631
1632 f = FindFirstFileW(src, &ffd);
1633 }else {
1634 src_len = get_parent_folder_name(source, source_len);
1635 if(src_len+2 >= MAX_PATH)
1636 return E_FAIL;
1637 memcpy(src, source, src_len*sizeof(WCHAR));
1638 if(src_len)
1639 src[src_len++] = '\\';
1640
1641 f = FindFirstFileW(source, &ffd);
1642 }
1643 if(f == INVALID_HANDLE_VALUE)
1644 return CTL_E_PATHNOTFOUND;
1645
1646 dst[dst_len++] = '\\';
1647 dst[dst_len] = 0;
1648
1649 do {
1650 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1651 continue;
1652 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
1653 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
1654 continue;
1655
1656 name_len = strlenW(ffd.cFileName);
1657 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
1658 FindClose(f);
1659 return E_FAIL;
1660 }
1661 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
1662 dst[dst_len+name_len] = 0;
1663 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
1664 src[src_len+name_len] = '\\';
1665 src[src_len+name_len+1] = '*';
1666 src[src_len+name_len+2] = 0;
1667
1668 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
1669
1670 if(!CreateDirectoryW(dst, NULL)) {
1671 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
1672 tmp = GetFileAttributesW(dst);
1673 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
1674 FindClose(f);
1675 return CTL_E_FILEALREADYEXISTS;
1676 }
1677 }else {
1678 FindClose(f);
1679 return create_error(GetLastError());
1680 }
1681 return create_error(GetLastError());
1682 }
1683 copied = TRUE;
1684
1685 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
1686 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
1687 FindClose(f);
1688 return hr;
1689 }
1690
1691 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
1692 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
1693 FindClose(f);
1694 return hr;
1695 }
1696 } while(FindNextFileW(f, &ffd));
1697 FindClose(f);
1698
1699 return copied ? S_OK : CTL_E_PATHNOTFOUND;
1700 }
1701
1702 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
1703 BSTR Destination, VARIANT_BOOL OverWriteFiles)
1704 {
1705 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
1706
1707 if(!Source || !Destination)
1708 return E_POINTER;
1709
1710 return copy_folder(Source, SysStringLen(Source), Destination,
1711 SysStringLen(Destination), OverWriteFiles);
1712 }
1713
1714 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
1715 IFolder **folder)
1716 {
1717 BOOL ret;
1718
1719 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
1720
1721 ret = CreateDirectoryW(path, NULL);
1722 if (!ret)
1723 {
1724 *folder = NULL;
1725 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
1726 return HRESULT_FROM_WIN32(GetLastError());
1727 }
1728
1729 return create_folder(folder);
1730 }
1731
1732 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR FileName,
1733 VARIANT_BOOL Overwrite, VARIANT_BOOL Unicode,
1734 ITextStream **ppts)
1735 {
1736 FIXME("%p %s %d %d %p\n", iface, debugstr_w(FileName), Overwrite, Unicode, ppts);
1737
1738 return E_NOTIMPL;
1739 }
1740
1741 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
1742 IOMode mode, VARIANT_BOOL create,
1743 Tristate format, ITextStream **stream)
1744 {
1745 FIXME("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
1746 return create_textstream(mode, stream);
1747 }
1748
1749 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
1750 StandardStreamTypes StandardStreamType,
1751 VARIANT_BOOL Unicode,
1752 ITextStream **ppts)
1753 {
1754 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
1755
1756 return E_NOTIMPL;
1757 }
1758
1759 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
1760 {
1761 static WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
1762 DWORDLONG version;
1763 WORD a, b, c, d;
1764
1765 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
1766 a = (WORD)( version >> 48);
1767 b = (WORD)((version >> 32) & 0xffff);
1768 c = (WORD)((version >> 16) & 0xffff);
1769 d = (WORD)( version & 0xffff);
1770
1771 sprintfW(ver, fmtW, a, b, c, d);
1772 }
1773
1774 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
1775 {
1776 static const WCHAR rootW[] = {'\\',0};
1777 VS_FIXEDFILEINFO *info;
1778 WCHAR ver[30];
1779 void *ptr;
1780 DWORD len;
1781 BOOL ret;
1782
1783 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
1784
1785 len = GetFileVersionInfoSizeW(name, NULL);
1786 if (!len)
1787 return HRESULT_FROM_WIN32(GetLastError());
1788
1789 ptr = heap_alloc(len);
1790 if (!GetFileVersionInfoW(name, 0, len, ptr))
1791 {
1792 heap_free(ptr);
1793 return HRESULT_FROM_WIN32(GetLastError());
1794 }
1795
1796 ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
1797 heap_free(ptr);
1798 if (!ret)
1799 return HRESULT_FROM_WIN32(GetLastError());
1800
1801 get_versionstring(info, ver);
1802 *version = SysAllocString(ver);
1803 TRACE("version=%s\n", debugstr_w(ver));
1804
1805 return S_OK;
1806 }
1807
1808 static const struct IFileSystem3Vtbl filesys_vtbl =
1809 {
1810 filesys_QueryInterface,
1811 filesys_AddRef,
1812 filesys_Release,
1813 filesys_GetTypeInfoCount,
1814 filesys_GetTypeInfo,
1815 filesys_GetIDsOfNames,
1816 filesys_Invoke,
1817 filesys_get_Drives,
1818 filesys_BuildPath,
1819 filesys_GetDriveName,
1820 filesys_GetParentFolderName,
1821 filesys_GetFileName,
1822 filesys_GetBaseName,
1823 filesys_GetExtensionName,
1824 filesys_GetAbsolutePathName,
1825 filesys_GetTempName,
1826 filesys_DriveExists,
1827 filesys_FileExists,
1828 filesys_FolderExists,
1829 filesys_GetDrive,
1830 filesys_GetFile,
1831 filesys_GetFolder,
1832 filesys_GetSpecialFolder,
1833 filesys_DeleteFile,
1834 filesys_DeleteFolder,
1835 filesys_MoveFile,
1836 filesys_MoveFolder,
1837 filesys_CopyFile,
1838 filesys_CopyFolder,
1839 filesys_CreateFolder,
1840 filesys_CreateTextFile,
1841 filesys_OpenTextFile,
1842 filesys_GetStandardStream,
1843 filesys_GetFileVersion
1844 };
1845
1846 static IFileSystem3 filesystem = { &filesys_vtbl };
1847
1848 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1849 {
1850 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
1851
1852 return IFileSystem3_QueryInterface(&filesystem, riid, ppv);
1853 }