Fix for DeviceIoControl masking FILE_DEVICE_FILE_SYSTEM incorrectly.
[reactos.git] / reactos / lib / ole32 / storage.c
1 /* Compound Storage
2 *
3 * Implemented using the documentation of the LAOLA project at
4 * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
5 * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
6 *
7 * Copyright 1998 Marcus Meissner
8 */
9
10 #include <time.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include <windows.h>
16 #include <ddk/ntddk.h>
17 #include <ole32/ole32.h>
18 #include <compobj.h>
19 #include <storage32.h>
20
21 #include <debug.h>
22
23 struct storage_header {
24 BYTE magic[8]; /* 00: magic */
25 BYTE unknown1[36]; /* 08: unknown */
26 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
27 DWORD root_startblock;/* 30: root storage first big block */
28 DWORD unknown2[2]; /* 34: unknown */
29 DWORD sbd_startblock; /* 3C: small block depot first big block */
30 DWORD unknown3[3]; /* 40: unknown */
31 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
32 };
33 struct storage_pps_entry {
34 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
35 WORD pps_sizeofname; /* 40: namelength in bytes */
36 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
37 BYTE pps_unknown0; /* 43: unknown */
38 DWORD pps_prev; /* 44: previous pps */
39 DWORD pps_next; /* 48: next pps */
40 DWORD pps_dir; /* 4C: directory pps */
41 GUID pps_guid; /* 50: class ID */
42 DWORD pps_unknown1; /* 60: unknown */
43 FILETIME pps_ft1; /* 64: filetime1 */
44 FILETIME pps_ft2; /* 70: filetime2 */
45 DWORD pps_sb; /* 74: data startblock */
46 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
47 DWORD pps_unknown2; /* 7C: unknown */
48 };
49
50 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
51 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
52 #define STORAGE_CHAINENTRY_FREE 0xffffffff
53
54
55 //static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
56 //static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
57 //static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
58
59 #define BIGSIZE 512
60 #define SMALLSIZE 64
61
62 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
63
64 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
65 static ICOM_VTABLE(IStorage16) stvt16;
66 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
67 static ICOM_VTABLE(IStream16) strvt16;
68 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
69
70 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
71 static void _create_istorage16(LPSTORAGE16 *stg);
72 static void _create_istream16(LPSTREAM16 *str);
73
74 #define IMPLEMENTED 1
75
76
77 /******************************************************************************
78 * STORAGE_get_big_block [Internal]
79 *
80 * Reading OLE compound storage
81 */
82 static BOOL
83 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
84 assert(n>=-1);
85 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
86 Print(MID_TRACE, (" seek failed (%ld)\n",GetLastError()));
87 return FALSE;
88 }
89 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
90 if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
91 Print(MID_TRACE, ("(block size %d): read didn't read (%ld)\n",n,GetLastError()));
92 assert(0);
93 return FALSE;
94 }
95 return TRUE;
96 }
97
98 /******************************************************************************
99 * STORAGE_put_big_block [INTERNAL]
100 */
101 static BOOL
102 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
103 assert(n>=-1);
104 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
105 Print(MID_TRACE, (" seek failed (%ld)\n",GetLastError()));
106 return FALSE;
107 }
108 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
109 if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
110 Print(MID_TRACE, (" write failed (%ld)\n",GetLastError()));
111 return FALSE;
112 }
113 return TRUE;
114 }
115
116 /******************************************************************************
117 * STORAGE_get_next_big_blocknr [INTERNAL]
118 */
119 static int
120 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
121 INT bbs[BIGSIZE/sizeof(INT)];
122 struct storage_header sth;
123
124 READ_HEADER;
125
126 assert(blocknr>>7<sth.num_of_bbd_blocks);
127 if (sth.bbd_list[blocknr>>7]==0xffffffff)
128 return -5;
129 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
130 return -5;
131 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
132 return bbs[blocknr&0x7f];
133 }
134
135 /******************************************************************************
136 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
137 */
138 static int
139 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
140 INT bbs[BIGSIZE/sizeof(INT)];
141 int lastblock = -1;
142 struct storage_header sth;
143
144 READ_HEADER;
145
146 assert(blocknr>=0);
147 while (nr--) {
148 assert((blocknr>>7)<sth.num_of_bbd_blocks);
149 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
150
151 /* simple caching... */
152 if (lastblock!=sth.bbd_list[blocknr>>7]) {
153 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
154 lastblock = sth.bbd_list[blocknr>>7];
155 }
156 blocknr = bbs[blocknr&0x7f];
157 }
158 return blocknr;
159 }
160
161 /******************************************************************************
162 * STORAGE_get_root_pps_entry [Internal]
163 */
164 static BOOL
165 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
166 int blocknr,i;
167 BYTE block[BIGSIZE];
168 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
169 struct storage_header sth;
170
171 READ_HEADER;
172 blocknr = sth.root_startblock;
173 while (blocknr>=0) {
174 assert(STORAGE_get_big_block(hf,blocknr,block));
175 for (i=0;i<4;i++) {
176 if (!stde[i].pps_sizeofname)
177 continue;
178 if (stde[i].pps_type==5) {
179 *pstde=stde[i];
180 return TRUE;
181 }
182 }
183 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
184 }
185 return FALSE;
186 }
187
188 /******************************************************************************
189 * STORAGE_get_small_block [INTERNAL]
190 */
191 static BOOL
192 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
193 BYTE block[BIGSIZE];
194 int bigblocknr;
195 struct storage_pps_entry root;
196
197 assert(blocknr>=0);
198 assert(STORAGE_get_root_pps_entry(hf,&root));
199 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
200 assert(bigblocknr>=0);
201 assert(STORAGE_get_big_block(hf,bigblocknr,block));
202
203 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
204 return TRUE;
205 }
206
207 /******************************************************************************
208 * STORAGE_put_small_block [INTERNAL]
209 */
210 static BOOL
211 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
212 BYTE block[BIGSIZE];
213 int bigblocknr;
214 struct storage_pps_entry root;
215
216 assert(blocknr>=0);
217
218 assert(STORAGE_get_root_pps_entry(hf,&root));
219 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
220 assert(bigblocknr>=0);
221 assert(STORAGE_get_big_block(hf,bigblocknr,block));
222
223 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
224 assert(STORAGE_put_big_block(hf,bigblocknr,block));
225 return TRUE;
226 }
227
228 /******************************************************************************
229 * STORAGE_get_next_small_blocknr [INTERNAL]
230 */
231 static int
232 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
233 BYTE block[BIGSIZE];
234 LPINT sbd = (LPINT)block;
235 int bigblocknr;
236 struct storage_header sth;
237
238 READ_HEADER;
239 assert(blocknr>=0);
240 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
241 assert(bigblocknr>=0);
242 assert(STORAGE_get_big_block(hf,bigblocknr,block));
243 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
244 return sbd[blocknr & (128-1)];
245 }
246
247 /******************************************************************************
248 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
249 */
250 static int
251 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
252 int lastblocknr;
253 BYTE block[BIGSIZE];
254 LPINT sbd = (LPINT)block;
255 struct storage_header sth;
256
257 READ_HEADER;
258 lastblocknr=-1;
259 assert(blocknr>=0);
260 while ((nr--) && (blocknr>=0)) {
261 if (lastblocknr/128!=blocknr/128) {
262 int bigblocknr;
263 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
264 assert(bigblocknr>=0);
265 assert(STORAGE_get_big_block(hf,bigblocknr,block));
266 lastblocknr = blocknr;
267 }
268 assert(lastblocknr>=0);
269 lastblocknr=blocknr;
270 blocknr=sbd[blocknr & (128-1)];
271 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
272 }
273 return blocknr;
274 }
275
276 /******************************************************************************
277 * STORAGE_get_pps_entry [INTERNAL]
278 */
279 static int
280 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
281 int blocknr;
282 BYTE block[BIGSIZE];
283 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
284 struct storage_header sth;
285
286 READ_HEADER;
287 /* we have 4 pps entries per big block */
288 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
289 assert(blocknr>=0);
290 assert(STORAGE_get_big_block(hf,blocknr,block));
291
292 *pstde=*stde;
293 return 1;
294 }
295
296 /******************************************************************************
297 * STORAGE_put_pps_entry [Internal]
298 */
299 static int
300 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
301 int blocknr;
302 BYTE block[BIGSIZE];
303 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
304 struct storage_header sth;
305
306 READ_HEADER;
307
308 /* we have 4 pps entries per big block */
309 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
310 assert(blocknr>=0);
311 assert(STORAGE_get_big_block(hf,blocknr,block));
312 *stde=*pstde;
313 assert(STORAGE_put_big_block(hf,blocknr,block));
314 return 1;
315 }
316
317 /******************************************************************************
318 * STORAGE_look_for_named_pps [Internal]
319 */
320 static int
321 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
322 struct storage_pps_entry stde;
323 int ret;
324
325 if (n==-1)
326 return -1;
327 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
328 return -1;
329
330 if (!lstrcmpW(name,stde.pps_rawname))
331 return n;
332 if (stde.pps_prev != -1) {
333 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
334 if (ret!=-1)
335 return ret;
336 }
337 if (stde.pps_next != -1) {
338 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
339 if (ret!=-1)
340 return ret;
341 }
342 return -1;
343 }
344
345 /******************************************************************************
346 * STORAGE_dump_pps_entry [Internal]
347 *
348 * FIXME
349 * Function is unused
350 */
351 void
352 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
353 #if 0
354 char name[33];
355
356 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
357 if (!stde->pps_sizeofname)
358 return;
359 Print(MAX_TRACE, ("name: %s\n",name));
360 Print(MAX_TRACE, ("type: %d\n",stde->pps_type));
361 Print(MAX_TRACE, ("prev pps: %ld\n",stde->pps_prev));
362 Print(MAX_TRACE, ("next pps: %ld\n",stde->pps_next));
363 Print(MAX_TRACE, ("dir pps: %ld\n",stde->pps_dir));
364 Print(MAX_TRACE, ("guid: %s\n",PRINT_GUID(&(stde->pps_guid))));
365 if (stde->pps_type !=2) {
366 time_t t;
367 DWORD dw;
368 RtlTimeToSecondsSince1970(&(stde->pps_ft1),&dw);
369 t = dw;
370 Print(MAX_TRACE, ("ts1: %s\n",ctime(&t)));
371 RtlTimeToSecondsSince1970(&(stde->pps_ft2),&dw);
372 t = dw;
373 Print(MAX_TRACE, ("ts2: %s\n",ctime(&t)));
374 }
375 Print(MAX_TRACE, ("startblock: %ld\n",stde->pps_sb));
376 Print(MAX_TRACE, ("size: %ld\n",stde->pps_size));
377 #endif
378 }
379
380 /******************************************************************************
381 * STORAGE_init_storage [INTERNAL]
382 */
383 static BOOL
384 STORAGE_init_storage(HFILE hf) {
385 BYTE block[BIGSIZE];
386 LPDWORD bbs;
387 struct storage_header *sth;
388 struct storage_pps_entry *stde;
389
390 assert(-1!=_llseek(hf,0,SEEK_SET));
391 /* block -1 is the storage header */
392 sth = (struct storage_header*)block;
393 memcpy(sth->magic,STORAGE_magic,8);
394 memset(sth->unknown1,0,sizeof(sth->unknown1));
395 memset(sth->unknown2,0,sizeof(sth->unknown2));
396 memset(sth->unknown3,0,sizeof(sth->unknown3));
397 sth->num_of_bbd_blocks = 1;
398 sth->root_startblock = 1;
399 sth->sbd_startblock = 0xffffffff;
400 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
401 sth->bbd_list[0] = 0;
402 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
403 /* block 0 is the big block directory */
404 bbs=(LPDWORD)block;
405 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
406 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
407 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
408 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
409 /* block 1 is the root directory entry */
410 memset(block,0x00,sizeof(block));
411 stde = (struct storage_pps_entry*)block;
412 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
413 sizeof(stde->pps_rawname)/sizeof(WCHAR));
414 stde->pps_sizeofname = (lstrlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
415 stde->pps_type = 5;
416 stde->pps_dir = -1;
417 stde->pps_next = -1;
418 stde->pps_prev = -1;
419 stde->pps_sb = 0xffffffff;
420 stde->pps_size = 0;
421 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
422 return TRUE;
423 }
424
425 /******************************************************************************
426 * STORAGE_set_big_chain [Internal]
427 */
428 static BOOL
429 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
430 BYTE block[BIGSIZE];
431 LPINT bbd = (LPINT)block;
432 int nextblocknr,bigblocknr;
433 struct storage_header sth;
434
435 READ_HEADER;
436 assert(blocknr!=type);
437 while (blocknr>=0) {
438 bigblocknr = sth.bbd_list[blocknr/128];
439 assert(bigblocknr>=0);
440 assert(STORAGE_get_big_block(hf,bigblocknr,block));
441
442 nextblocknr = bbd[blocknr&(128-1)];
443 bbd[blocknr&(128-1)] = type;
444 if (type>=0)
445 return TRUE;
446 assert(STORAGE_put_big_block(hf,bigblocknr,block));
447 type = STORAGE_CHAINENTRY_FREE;
448 blocknr = nextblocknr;
449 }
450 return TRUE;
451 }
452
453 /******************************************************************************
454 * STORAGE_set_small_chain [Internal]
455 */
456 static BOOL
457 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
458 BYTE block[BIGSIZE];
459 LPINT sbd = (LPINT)block;
460 int lastblocknr,nextsmallblocknr,bigblocknr;
461 struct storage_header sth;
462
463 READ_HEADER;
464
465 assert(blocknr!=type);
466 lastblocknr=-129;bigblocknr=-2;
467 while (blocknr>=0) {
468 /* cache block ... */
469 if (lastblocknr/128!=blocknr/128) {
470 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
471 assert(bigblocknr>=0);
472 assert(STORAGE_get_big_block(hf,bigblocknr,block));
473 }
474 lastblocknr = blocknr;
475 nextsmallblocknr = sbd[blocknr&(128-1)];
476 sbd[blocknr&(128-1)] = type;
477 assert(STORAGE_put_big_block(hf,bigblocknr,block));
478 if (type>=0)
479 return TRUE;
480 type = STORAGE_CHAINENTRY_FREE;
481 blocknr = nextsmallblocknr;
482 }
483 return TRUE;
484 }
485
486 /******************************************************************************
487 * STORAGE_get_free_big_blocknr [Internal]
488 */
489 static int
490 STORAGE_get_free_big_blocknr(HFILE hf) {
491 BYTE block[BIGSIZE];
492 LPINT sbd = (LPINT)block;
493 int lastbigblocknr,i,curblock,bigblocknr;
494 struct storage_header sth;
495
496 READ_HEADER;
497 curblock = 0;
498 lastbigblocknr = -1;
499 bigblocknr = sth.bbd_list[curblock];
500 while (curblock<sth.num_of_bbd_blocks) {
501 assert(bigblocknr>=0);
502 assert(STORAGE_get_big_block(hf,bigblocknr,block));
503 for (i=0;i<128;i++)
504 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
505 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
506 assert(STORAGE_put_big_block(hf,bigblocknr,block));
507 memset(block,0x42,sizeof(block));
508 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
509 return i+curblock*128;
510 }
511 lastbigblocknr = bigblocknr;
512 bigblocknr = sth.bbd_list[++curblock];
513 }
514 bigblocknr = curblock*128;
515 /* since we have marked all blocks from 0 up to curblock*128-1
516 * the next free one is curblock*128, where we happily put our
517 * next large block depot.
518 */
519 memset(block,0xff,sizeof(block));
520 /* mark the block allocated and returned by this function */
521 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
522 assert(STORAGE_put_big_block(hf,bigblocknr,block));
523
524 /* if we had a bbd block already (mostlikely) we need
525 * to link the new one into the chain
526 */
527 if (lastbigblocknr!=-1)
528 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
529 sth.bbd_list[curblock]=bigblocknr;
530 sth.num_of_bbd_blocks++;
531 assert(sth.num_of_bbd_blocks==curblock+1);
532 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
533
534 /* Set the end of the chain for the bigblockdepots */
535 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
536 /* add 1, for the first entry is used for the additional big block
537 * depot. (means we already used bigblocknr) */
538 memset(block,0x42,sizeof(block));
539 /* allocate this block (filled with 0x42) */
540 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
541 return bigblocknr+1;
542 }
543
544
545 /******************************************************************************
546 * STORAGE_get_free_small_blocknr [Internal]
547 */
548 static int
549 STORAGE_get_free_small_blocknr(HFILE hf) {
550 BYTE block[BIGSIZE];
551 LPINT sbd = (LPINT)block;
552 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
553 struct storage_pps_entry root;
554 struct storage_header sth;
555
556 READ_HEADER;
557 bigblocknr = sth.sbd_startblock;
558 curblock = 0;
559 lastbigblocknr = -1;
560 newblocknr = -1;
561 while (bigblocknr>=0) {
562 if (!STORAGE_get_big_block(hf,bigblocknr,block))
563 return -1;
564 for (i=0;i<128;i++)
565 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
566 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
567 newblocknr = i+curblock*128;
568 break;
569 }
570 if (i!=128)
571 break;
572 lastbigblocknr = bigblocknr;
573 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
574 curblock++;
575 }
576 if (newblocknr==-1) {
577 bigblocknr = STORAGE_get_free_big_blocknr(hf);
578 if (bigblocknr<0)
579 return -1;
580 READ_HEADER;
581 memset(block,0xff,sizeof(block));
582 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
583 if (!STORAGE_put_big_block(hf,bigblocknr,block))
584 return -1;
585 if (lastbigblocknr==-1) {
586 sth.sbd_startblock = bigblocknr;
587 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
588 return -1;
589 } else {
590 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
591 return -1;
592 }
593 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
594 return -1;
595 newblocknr = curblock*128;
596 }
597 /* allocate enough big blocks for storing the allocated small block */
598 if (!STORAGE_get_root_pps_entry(hf,&root))
599 return -1;
600 if (root.pps_sb==-1)
601 lastbigblocknr = -1;
602 else
603 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
604 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
605 /* we need to allocate more stuff */
606 bigblocknr = STORAGE_get_free_big_blocknr(hf);
607 if (bigblocknr<0)
608 return -1;
609 READ_HEADER;
610 if (root.pps_sb==-1) {
611 root.pps_sb = bigblocknr;
612 root.pps_size += BIGSIZE;
613 } else {
614 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
615 return -1;
616 root.pps_size += BIGSIZE;
617 }
618 lastbigblocknr = bigblocknr;
619 }
620 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
621 return -1;
622 if (!STORAGE_put_pps_entry(hf,0,&root))
623 return -1;
624 return newblocknr;
625 }
626
627 /******************************************************************************
628 * STORAGE_get_free_pps_entry [Internal]
629 */
630 static int
631 STORAGE_get_free_pps_entry(HFILE hf) {
632 int blocknr,i,curblock,lastblocknr;
633 BYTE block[BIGSIZE];
634 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
635 struct storage_header sth;
636
637 READ_HEADER;
638 blocknr = sth.root_startblock;
639 assert(blocknr>=0);
640 curblock=0;
641 while (blocknr>=0) {
642 if (!STORAGE_get_big_block(hf,blocknr,block))
643 return -1;
644 for (i=0;i<4;i++)
645 if (stde[i].pps_sizeofname==0) /* free */
646 return curblock*4+i;
647 lastblocknr = blocknr;
648 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
649 curblock++;
650 }
651 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
652 blocknr = STORAGE_get_free_big_blocknr(hf);
653 /* sth invalidated */
654 if (blocknr<0)
655 return -1;
656
657 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
658 return -1;
659 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
660 return -1;
661 memset(block,0,sizeof(block));
662 STORAGE_put_big_block(hf,blocknr,block);
663 return curblock*4;
664 }
665
666 /* --- IStream32 implementation */
667
668 typedef struct
669 {
670 /* IUnknown fields */
671 ICOM_VFIELD(IStream);
672 DWORD ref;
673 /* IStream32 fields */
674 struct storage_pps_entry stde;
675 int ppsent;
676 HFILE hf;
677 ULARGE_INTEGER offset;
678 } IStream32Impl;
679
680 /*****************************************************************************
681 * IStream32_QueryInterface [VTABLE]
682 */
683 HRESULT WINAPI IStream_fnQueryInterface(
684 IStream* iface,REFIID refiid,LPVOID *obj
685 ) {
686 ICOM_THIS(IStream32Impl,iface);
687
688 Print(MAX_TRACE, ("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj));
689 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
690 *obj = This;
691 return 0;
692 }
693 return OLE_E_ENUM_NOMORE;
694
695 }
696
697 /******************************************************************************
698 * IStream32_AddRef [VTABLE]
699 */
700 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
701 ICOM_THIS(IStream32Impl,iface);
702 return ++(This->ref);
703 }
704
705 /******************************************************************************
706 * IStream32_Release [VTABLE]
707 */
708 ULONG WINAPI IStream_fnRelease(IStream* iface) {
709 #if 0
710 ICOM_THIS(IStream32Impl,iface);
711 FlushFileBuffers(This->hf);
712 This->ref--;
713 if (!This->ref) {
714 CloseHandle(This->hf);
715 SEGPTR_FREE(This);
716 return 0;
717 }
718 return This->ref;
719 #else
720 UNIMPLEMENTED;
721 return 0;
722 #endif
723 }
724
725
726 /******************************************************************************
727 * Storage API functions
728 */
729
730 /******************************************************************************
731 * StgCreateDocFile16 [STORAGE.1]
732 */
733 HRESULT WINAPI StgCreateDocFile16(
734 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
735 ) {
736 UNIMPLEMENTED;
737 return S_OK;
738 }
739
740 /******************************************************************************
741 * StgIsStorageFile16 [STORAGE.5]
742 */
743 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
744 UNIMPLEMENTED;
745 return S_OK;
746 }
747
748 /******************************************************************************
749 * StgIsStorageFile [OLE32.146]
750 */
751 HRESULT WINAPI
752 StgIsStorageFile(LPCOLESTR fn)
753 {
754 #if 0
755 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
756 HRESULT ret = StgIsStorageFile16(xfn);
757
758 HeapFree(GetProcessHeap(),0,xfn);
759 return ret;
760 #else
761 UNIMPLEMENTED;
762 return S_OK;
763 #endif
764 }
765
766
767 /******************************************************************************
768 * StgOpenStorage16 [STORAGE.3]
769 */
770 HRESULT WINAPI StgOpenStorage16(
771 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
772 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
773 ) {
774 UNIMPLEMENTED;
775 return S_OK;
776 }
777
778