1 /*
2 * storage.cpp
3 * swift
4 *
5 * Created by Arno Bakker.
6 * Copyright 2009-2016 TECHNISCHE UNIVERSITEIT DELFT. All rights reserved.
7 *
8 * TODO:
9 * - Unicode?
10 * - Slow resume after alloc big file (Win32, work on swift-trunk)
11 */
12
13 #include "swift.h"
14 #include "compat.h"
15
16 #include <vector>
17 #include <utility>
18
19 using namespace swift;
20
21
22 const std::string Storage::MULTIFILE_PATHNAME = "META-INF-multifilespec.txt";
23 const std::string Storage::MULTIFILE_PATHNAME_FILE_SEP = "/";
24
25 #define DEBUGSTORAGE 0
26
27
Storage(std::string ospathname,std::string destdir,int td,uint64_t live_disc_wnd_bytes,std::string metamfspecospathname)28 Storage::Storage(std::string ospathname, std::string destdir, int td, uint64_t live_disc_wnd_bytes,
29 std::string metamfspecospathname) :
30 Operational(),
31 state_(STOR_STATE_INIT),
32 os_pathname_(ospathname), destdir_(destdir), ht_(NULL), spec_size_(0),
33 single_fd_(-1), reserved_size_(-1), total_size_from_spec_(-1), last_sf_(NULL),
34 td_(td), alloc_cb_(NULL), live_disc_wnd_bytes_(live_disc_wnd_bytes), meta_mfspec_os_pathname_(metamfspecospathname)
35 {
36 // SIGNPEAK
37 if (live_disc_wnd_bytes > 0 && live_disc_wnd_bytes != POPT_LIVE_DISC_WND_ALL) {
38 state_ = STOR_STATE_SINGLE_LIVE_WRAP;
39 (void)OpenSingleFile();
40 return;
41 }
42
43 std::string filename = os_pathname_;
44
45 int64_t fsize = file_size_by_path_utf8(ospathname.c_str());
46 if (fsize < 0 && errno == ENOENT) {
47 // check if the metafile exists somewhere else
48 filename = meta_mfspec_os_pathname_;
49
50 fsize = file_size_by_path_utf8(metamfspecospathname.c_str());
51 if (fsize < 0 && errno == ENOENT) {
52 // File does not exist, assume we're a client and all will be revealed
53 // (single file, multi-spec) when chunks come in.
54 return;
55 }
56 }
57
58 // File exists. Check first bytes to see if a multifile-spec
59 FILE *fp = fopen_utf8(filename.c_str(),"rb");
60 if (!fp) {
61 dprintf("%s %s storage: File exists, but error opening\n", tintstr(), roothashhex().c_str());
62 print_error("Could not open existing storage file");
63 SetBroken();
64 return;
65 }
66
67 char readbuf[1024];
68 int ret = fread(readbuf,sizeof(char),MULTIFILE_PATHNAME.length(),fp);
69 fclose(fp);
70 if (ret < 0) {
71 SetBroken();
72 return;
73 }
74
75 if (!strncmp(readbuf,MULTIFILE_PATHNAME.c_str(),MULTIFILE_PATHNAME.length())) {
76 // Pathname points to a multi-file spec, assume we're seeding
77 // Arno, 2013-03-06: Not correct for a spec that doesn't fit in chunk 0,
78 // should attempt to parse spec, if good then _COMPLETE otherwise wait
79 // for chunks 1,2... and reparse.
80 //
81 state_ = STOR_STATE_MFSPEC_COMPLETE;
82
83 dprintf("%s %s storage: Found multifile-spec, will seed it.\n", tintstr(), roothashhex().c_str());
84
85 StorageFile *sf = new StorageFile(MULTIFILE_PATHNAME,0,fsize,filename);
86 if (!sf->IsOperational()) {
87 print_error("storage: multi-file spec file is not operational");
88 SetBroken();
89 return;
90 }
91 sfs_.push_back(sf);
92 if (ParseSpec(sf) < 0) {
93 print_error("storage: error parsing multi-file spec");
94 SetBroken();
95 }
96 } else {
97 // Normal swarm
98 dprintf("%s %s storage: Found single file, will check it.\n", tintstr(), roothashhex().c_str());
99
100 state_ = STOR_STATE_SINGLE_FILE;
101 (void)OpenSingleFile();
102 }
103 }
104
105
~Storage()106 Storage::~Storage()
107 {
108 if (single_fd_ != -1)
109 close(single_fd_);
110
111 storage_files_t::iterator iter;
112 for (iter = sfs_.begin(); iter < sfs_.end(); iter++) {
113 StorageFile *sf = *iter;
114 delete sf;
115 }
116 sfs_.clear();
117 }
118
119
Write(const void * buf,size_t nbyte,int64_t offset)120 ssize_t Storage::Write(const void *buf, size_t nbyte, int64_t offset)
121 {
122 if (DEBUGSTORAGE)
123 dprintf("%s %s storage: Write: fd %d nbyte " PRISIZET " off %" PRIi64 " state %" PRIi32 "\n", tintstr(),
124 roothashhex().c_str(), single_fd_, nbyte,offset,state_);
125
126 if (state_ == STOR_STATE_SINGLE_FILE) {
127 return pwrite(single_fd_, buf, nbyte, offset);
128 } else if (state_ == STOR_STATE_SINGLE_LIVE_WRAP) { // SIGNPEAK
129 int64_t newoff = offset % live_disc_wnd_bytes_;
130
131 if (DEBUGSTORAGE)
132 dprintf("%s %d ?data writing disk %" PRIi64 " window %" PRIu64 "\n",tintstr(), 0, newoff, live_disc_wnd_bytes_);
133
134 if (newoff+nbyte > live_disc_wnd_bytes_) {
135 // Writing more than window
136 size_t firstbyte = live_disc_wnd_bytes_ - newoff;
137 if (DEBUGSTORAGE)
138 dprintf("%s %d ?data writing disk %" PRIi64 " firstbyte " PRISIZET "\n",tintstr(), 0, newoff, firstbyte);
139 int ret = pwrite(single_fd_, buf, firstbyte, newoff);
140 if (ret < 0)
141 return ret;
142 else
143 return Write(((char *)buf)+firstbyte,nbyte-firstbyte,offset+firstbyte);
144 } else
145 return pwrite(single_fd_, buf, nbyte, newoff);
146 }
147
148 // MULTIFILE
149 if (state_ == STOR_STATE_INIT) {
150 if (offset != 0) {
151 dprintf("%s %s storage: Write: First write to offset >0, assume live\n", tintstr(), roothashhex().c_str());
152 //errno = EINVAL;
153 //return -1;
154 }
155
156 if (DEBUGSTORAGE)
157 dprintf("%s %s storage: Write: chunk 0\n", tintstr(), roothashhex().c_str());
158
159 // Check for multifile spec. If present, multifile, otherwise single
160 if (!strncmp((const char *)buf,MULTIFILE_PATHNAME.c_str(),strlen(MULTIFILE_PATHNAME.c_str()))) {
161 dprintf("%s %s storage: Write: Is multifile\n", tintstr(), roothashhex().c_str());
162
163 // multifile entry will fit into first chunk
164 const char *bufstr = (const char *)buf;
165 int n = sscanf((const char *)&bufstr[strlen(MULTIFILE_PATHNAME.c_str())+1],"%" PRIi64 "",&spec_size_);
166 if (n != 1) {
167 errno = EINVAL;
168 return -1;
169 }
170
171 //dprintf("%s %s storage: Write: multifile: specsize %" PRIi64 "\n", tintstr(), roothashhex().c_str(), spec_size_ );
172
173 // Create StorageFile for multi-file spec.
174 StorageFile *sf = new StorageFile(MULTIFILE_PATHNAME,0,spec_size_,os_pathname_);
175 sfs_.push_back(sf);
176
177 // Write all, or part of spec and set state_
178 return WriteSpecPart(sf,buf,nbyte,offset);
179 } else {
180 // Is a single file swarm.
181 state_ = STOR_STATE_SINGLE_FILE;
182
183 int ret = OpenSingleFile();
184 if (ret < 0)
185 return -1;
186
187 // Write chunk to file via recursion.
188 return Write(buf,nbyte,offset);
189 }
190 } else if (state_ == STOR_STATE_MFSPEC_SIZE_KNOWN) {
191 StorageFile *sf = sfs_[0];
192
193 dprintf("%s %s storage: Write: mf spec size known\n", tintstr(), roothashhex().c_str());
194
195 return WriteSpecPart(sf,buf,nbyte,offset);
196 } else {
197 // state_ == STOR_STATE_MFSPEC_COMPLETE;
198 //dprintf("%s %s storage: Write: complete\n", tintstr(), roothashhex().c_str());
199
200 StorageFile *sf = NULL;
201 if (last_sf_ != NULL && offset >= last_sf_->GetStart() && offset <= last_sf_->GetEnd())
202 sf = last_sf_;
203 else {
204 sf = FindStorageFile(offset);
205 if (sf == NULL) {
206 dprintf("%s %s storage: Write: File not found!\n", tintstr(), roothashhex().c_str());
207 errno = EINVAL;
208 return -1;
209 }
210 last_sf_ = sf;
211 }
212
213 std::pair<int64_t,int64_t> ht = WriteBuffer(sf,buf,nbyte,offset);
214 if (ht.first == -1) {
215 errno = EINVAL;
216 return -1;
217 }
218
219 //dprintf("%s %s storage: Write: complete: first %" PRIi64 " second %" PRIi64 "\n", tintstr(), roothashhex().c_str(), ht.first, ht.second);
220
221 if (ht.second > 0) {
222 // Write tail to next StorageFile(s) using recursion
223 const char *bufstr = (const char *)buf;
224 int ret = Write(&bufstr[ht.first], ht.second, offset+ht.first);
225 if (ret < 0)
226 return ret;
227 else
228 return ht.first+ret;
229 } else
230 return ht.first;
231 }
232 }
233
234
WriteSpecPart(StorageFile * sf,const void * buf,size_t nbyte,int64_t offset)235 int Storage::WriteSpecPart(StorageFile *sf, const void *buf, size_t nbyte, int64_t offset)
236 {
237 //dprintf("%s %s storage: WriteSpecPart: %s %d %" PRIi64 "\n", tintstr(), roothashhex().c_str(), sf->GetSpecPathName().c_str(), nbyte, offset );
238
239 std::pair<int64_t,int64_t> ht = WriteBuffer(sf,buf,nbyte,offset);
240 if (ht.first == -1) {
241 errno = EINVAL;
242 return -1;
243 }
244
245 if (offset+ht.first == sf->GetEnd()+1) {
246 // Wrote last part of spec
247 state_ = STOR_STATE_MFSPEC_COMPLETE;
248
249 int ret = ParseSpec(sf);
250 if (ret < 0) {
251 errno = EINVAL;
252 return -1;
253 }
254
255 // We know exact size after chunk 0, inform hash tree (which doesn't
256 // know until chunk N-1) is in.
257 ht_->set_size(GetSizeFromSpec());
258
259 // Resize all files
260 ret = ResizeReserved(GetSizeFromSpec());
261 if (ret < 0)
262 return ret;
263
264 // Write tail to next StorageFile(s) using recursion
265 const char *bufstr = (const char *)buf;
266 ret = Write(&bufstr[ht.first], ht.second, offset+ht.first);
267 if (ret < 0)
268 return ret;
269 else
270 return ht.first+ret;
271 } else {
272 state_ = STOR_STATE_MFSPEC_SIZE_KNOWN;
273 return ht.first;
274 }
275 }
276
277
278
WriteBuffer(StorageFile * sf,const void * buf,size_t nbyte,int64_t offset)279 std::pair<int64_t,int64_t> Storage::WriteBuffer(StorageFile *sf, const void *buf, size_t nbyte, int64_t offset)
280 {
281 //dprintf("%s %s storage: WriteBuffer: %s %d %" PRIi64 "\n", tintstr(), roothashhex().c_str(), sf->GetSpecPathName().c_str(), nbyte, offset );
282
283 int ret = -1;
284 if (offset+nbyte <= sf->GetEnd()+1) {
285 // Chunk belongs completely in sf
286 ret = sf->Write(buf,nbyte,offset - sf->GetStart());
287
288 //dprintf("%s %s storage: WriteBuffer: Write: covered ret %d\n", tintstr(), roothashhex().c_str(), ret );
289
290 if (ret < 0)
291 return std::make_pair(-1,-1);
292 else
293 return std::make_pair(nbyte,0);
294
295 } else {
296 int64_t head = sf->GetEnd()+1 - offset;
297 int64_t tail = nbyte - head;
298
299 // Write last part of file
300 ret = sf->Write(buf,head,offset - sf->GetStart());
301
302 //dprintf("%s %s storage: WriteBuffer: Write: partial ret %d\n", tintstr(), roothashhex().c_str(), ret );
303
304 if (ret < 0)
305 return std::make_pair(-1,-1);
306 else
307 return std::make_pair(head,tail);
308 }
309 }
310
311
312
313
FindStorageFile(int64_t offset)314 StorageFile * Storage::FindStorageFile(int64_t offset)
315 {
316 // Binary search for StorageFile that manages the given offset
317 int imin = 0, imax=sfs_.size()-1;
318 while (imax >= imin) {
319 int imid = (imin + imax) / 2;
320 if (offset >= sfs_[imid]->GetEnd()+1)
321 imin = imid + 1;
322 else if (offset < sfs_[imid]->GetStart())
323 imax = imid - 1;
324 else
325 return sfs_[imid];
326 }
327 // Should find it.
328 return NULL;
329 }
330
331
ParseSpec(StorageFile * sf)332 int Storage::ParseSpec(StorageFile *sf)
333 {
334 char *retstr = NULL,line[MULTIFILE_MAX_LINE+1];
335 FILE *fp = fopen_utf8(sf->GetOSPathName().c_str(),"rb");
336 if (fp == NULL) {
337 print_error("cannot open multifile-spec");
338 SetBroken();
339 return -1;
340 }
341
342 int64_t offset=0;
343 int ret=0;
344 while (1) {
345 retstr = fgets(line,MULTIFILE_MAX_LINE,fp);
346 if (retstr == NULL)
347 break;
348
349 // Format: "specpath filesize\n"
350 std::string pline(line);
351 size_t idx = pline.rfind(' ',pline.length()-1);
352
353 std::string specpath = pline.substr(0,idx);
354 std::string sizestr = pline.substr(idx+1,pline.length());
355
356 int64_t fsize=0;
357 int n = sscanf(sizestr.c_str(),"%" PRIi64 "",&fsize);
358 if (n == 0) {
359 ret = -1;
360 break;
361 }
362
363 // Check pathname safety
364 if (specpath.substr(0,1) == MULTIFILE_PATHNAME_FILE_SEP) {
365 // Must not start with /
366 ret = -1;
367 break;
368 }
369 idx = specpath.find("..",0);
370 if (idx != std::string::npos) {
371 // Must not contain .. path escapes
372 ret = -1;
373 break;
374 }
375
376 if (offset == 0) {
377 // sf already created for multifile-spec entry
378 offset += sf->GetSize();
379 } else {
380 // Convert specname to OS name
381 std::string ospath = destdir_+FILE_SEP;
382 ospath += Storage::spec2ospn(specpath);
383
384 StorageFile *sf = new StorageFile(specpath,offset,fsize,ospath);
385 if (!sf->IsOperational()) {
386 SetBroken();
387 return -1;
388 }
389 sfs_.push_back(sf);
390 offset += fsize;
391 }
392 }
393
394 // Assume: Multi-file spec sorted, so vector already sorted on offset
395 storage_files_t::iterator iter;
396 for (iter = sfs_.begin(); iter < sfs_.end(); iter++) {
397 StorageFile *sf = *iter;
398 dprintf("%s %s storage: parsespec: Got %s start %" PRIi64 " size %" PRIi64 "\n", tintstr(), roothashhex().c_str(),
399 sf->GetSpecPathName().c_str(), sf->GetStart(), sf->GetSize());
400 }
401
402 fclose(fp);
403 if (ret < 0) {
404 SetBroken();
405 return ret;
406 } else {
407 total_size_from_spec_ = offset;
408 return 0;
409 }
410 }
411
412
OpenSingleFile()413 int Storage::OpenSingleFile()
414 {
415 dprintf("%s %s storage: Opening single file %s\n", tintstr(), roothashhex().c_str(), os_pathname_.c_str());
416 single_fd_ = open_utf8(os_pathname_.c_str(),OPENFLAGS,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
417 if (single_fd_<0) {
418 single_fd_ = -1;
419 print_error("storage: cannot open single file");
420 SetBroken();
421 return -1;
422 }
423
424 // Perform postponed resize.
425 if (reserved_size_ != -1) {
426 int ret = ResizeReserved(reserved_size_);
427 if (ret < 0) {
428 close(single_fd_);
429 single_fd_ = -1;
430 SetBroken();
431 }
432 }
433
434 return single_fd_;
435 }
436
437
438
439
Read(void * buf,size_t nbyte,int64_t offset)440 ssize_t Storage::Read(void *buf, size_t nbyte, int64_t offset)
441 {
442 //dprintf("%s %s storage: Read: nbyte " PRISIZET " off %" PRIi64 "\n", tintstr(), roothashhex().c_str(), nbyte, offset );
443
444 if (state_ == STOR_STATE_SINGLE_FILE) {
445 return pread(single_fd_, buf, nbyte, offset);
446 } else if (state_ == STOR_STATE_SINGLE_LIVE_WRAP) {
447 int64_t newoff = offset % live_disc_wnd_bytes_;
448 dprintf("%s %d ?data reading disk %" PRIi64 " window %" PRIu64 "\n",tintstr(), 0, newoff, live_disc_wnd_bytes_);
449
450 return pread(single_fd_, buf, nbyte, newoff);
451 }
452
453
454 // MULTIFILE
455 if (state_ == STOR_STATE_INIT) {
456 errno = EINVAL;
457 return -1;
458 } else {
459 StorageFile *sf = NULL;
460 if (last_sf_ != NULL && offset >= last_sf_->GetStart() && offset <= last_sf_->GetEnd())
461 sf = last_sf_;
462 else {
463 sf = FindStorageFile(offset);
464 if (sf == NULL) {
465 errno = EINVAL;
466 return -1;
467 }
468 last_sf_ = sf;
469 //dprintf("%s %s storage: Read: Found file %s for off %" PRIi64 "\n", tintstr(), roothashhex().c_str(), sf->GetSpecPathName().c_str(), offset );
470 }
471
472 ssize_t ret = sf->Read(buf,nbyte,offset - sf->GetStart());
473 if (ret < 0)
474 return ret;
475
476 //dprintf("%s %s storage: Read: read %d\n", tintstr(), roothashhex().c_str(), ret );
477
478 if (ret < nbyte && offset+ret != ht_->size()) {
479 //dprintf("%s %s storage: Read: want %d more\n", tintstr(), roothashhex().c_str(), nbyte-ret );
480
481 // Not at end, and can fit more in buffer. Do recursion
482 char *bufstr = (char *)buf;
483 ssize_t newret = Read((void *)(bufstr+ret),nbyte-ret,offset+ret);
484 if (newret < 0)
485 return newret;
486 else
487 return ret + newret;
488 } else
489 return ret;
490 }
491 }
492
493
GetSizeFromSpec()494 int64_t Storage::GetSizeFromSpec()
495 {
496 if (state_ == STOR_STATE_SINGLE_FILE)
497 return -1;
498 else
499 return total_size_from_spec_;
500 }
501
502
503
GetReservedSize()504 int64_t Storage::GetReservedSize()
505 {
506 if (state_ == STOR_STATE_SINGLE_FILE) {
507 return file_size(single_fd_);
508 } else if (state_ != STOR_STATE_MFSPEC_COMPLETE)
509 return -1;
510
511 // MULTIFILE
512 storage_files_t::iterator iter;
513 int64_t totaldisksize=0;
514 for (iter = sfs_.begin(); iter < sfs_.end(); iter++) {
515 StorageFile *sf = *iter;
516
517 dprintf("storage: getdisksize: statting %s\n", sf->GetOSPathName().c_str());
518
519 int64_t fsize = file_size_by_path_utf8(sf->GetOSPathName().c_str());
520 if (fsize < 0) {
521 dprintf("%s %s storage: getdisksize: cannot stat file %s\n", tintstr(), roothashhex().c_str(),
522 sf->GetOSPathName().c_str());
523 return fsize;
524 } else
525 totaldisksize += fsize;
526 }
527
528 dprintf("storage: getdisksize: total already sized is %" PRIi64 "\n", totaldisksize);
529
530 return totaldisksize;
531 }
532
533
GetMinimalReservedSize()534 int64_t Storage::GetMinimalReservedSize()
535 {
536 if (state_ == STOR_STATE_SINGLE_FILE) {
537 return 0;
538 } else if (state_ != STOR_STATE_MFSPEC_COMPLETE)
539 return -1;
540
541 StorageFile *sf = sfs_[0];
542 return sf->GetSize();
543 }
544
545
ResizeReserved(int64_t size)546 int Storage::ResizeReserved(int64_t size)
547 {
548 // Arno, 2012-05-24: File allocation slow on Win32 without sparse files,
549 // make this detectable.
550 if (alloc_cb_ != NULL) {
551 alloc_cb_(td_,bin_t::NONE);
552 alloc_cb_ = NULL; // One time callback
553 }
554
555 if (state_ == STOR_STATE_SINGLE_FILE) {
556 dprintf("%s %s storage: Resizing single file %d to %" PRIi64 "\n", tintstr(), roothashhex().c_str(), single_fd_, size);
557 return file_resize(single_fd_,size);
558 } else if (state_ == STOR_STATE_INIT) {
559 dprintf("%s %s storage: Postpone resize to %" PRIi64 "\n", tintstr(), roothashhex().c_str(), size);
560 reserved_size_ = size;
561 return 0;
562 } else if (state_ != STOR_STATE_MFSPEC_COMPLETE)
563 return -1;
564
565 // MULTIFILE
566 if (size > GetReservedSize()) {
567 dprintf("%s %s storage: Resizing multi file to %" PRIi64 "\n", tintstr(), roothashhex().c_str(), size);
568
569 // Resize files to wanted size, so pread() / pwrite() works for all offsets.
570 storage_files_t::iterator iter;
571 for (iter = sfs_.begin(); iter < sfs_.end(); iter++) {
572 StorageFile *sf = *iter;
573 int ret = sf->ResizeReserved();
574 if (ret < 0)
575 return ret;
576 }
577 } else
578 dprintf("%s %s storage: Resize multi-file to <= %" PRIi64 ", ignored\n", tintstr(), roothashhex().c_str(), size);
579
580 return 0;
581 }
582
583
spec2ospn(std::string specpn)584 std::string Storage::spec2ospn(std::string specpn)
585 {
586 std::string dest = specpn;
587 // compat.h I/O layer does UTF-8 to OS encoding
588 if (MULTIFILE_PATHNAME_FILE_SEP != FILE_SEP) {
589 // Replace OS filesep with spec
590 swift::stringreplace(dest,MULTIFILE_PATHNAME_FILE_SEP,FILE_SEP);
591 }
592 return dest;
593 }
594
os2specpn(std::string ospn)595 std::string Storage::os2specpn(std::string ospn)
596 {
597 std::string dest = ospn;
598 // compat.h I/O layer does OS to UTF-8 encoding
599 if (MULTIFILE_PATHNAME_FILE_SEP != FILE_SEP) {
600 // Replace OS filesep with spec
601 swift::stringreplace(dest,FILE_SEP,MULTIFILE_PATHNAME_FILE_SEP);
602 }
603 return dest;
604 }
605
606
607
608 /*
609 * StorageFile
610 */
611
612
613
StorageFile(std::string specpath,int64_t start,int64_t size,std::string ospath)614 StorageFile::StorageFile(std::string specpath, int64_t start, int64_t size, std::string ospath) :
615 Operational(),
616 fd_(-1)
617 {
618 spec_pathname_ = specpath;
619 start_ = start;
620 end_ = start+size-1;
621 os_pathname_ = ospath;
622
623 //fprintf(stderr,"StorageFile: os_pathname_ is %s\n", os_pathname_.c_str() );
624
625 std::string normospath = os_pathname_;
626 #ifdef _WIN32
627 swift::stringreplace(normospath,"\\\\","\\");
628 #else
629 swift::stringreplace(normospath,"//","/");
630 #endif
631
632 // Handle subdirs, if not multifilespec.txt
633 if (start_ != 0 && normospath.find(FILE_SEP,0) != std::string::npos) {
634 // Path contains dirs, make them
635 size_t i = 0;
636 while (true) {
637 i = normospath.find(FILE_SEP,i+1);
638 if (i == std::string::npos)
639 break;
640 std::string path = normospath.substr(0,i);
641 #ifdef _WIN32
642 if (path.size() == 2 && path[1] == ':')
643 // Windows drive spec, ignore
644 continue;
645 #endif
646 int ret = file_exists_utf8(path.c_str());
647 if (ret <= 0) {
648 ret = mkdir_utf8(path.c_str());
649
650 //fprintf(stderr,"StorageFile: mkdir %s returns %d\n", path.c_str(), ret );
651
652 if (ret < 0) {
653 SetBroken();
654 return;
655 }
656 } else if (ret == 1) {
657 // Something already exists and it is not a dir
658
659 dprintf("StorageFile: exists %s but is not dir %d\n", path.c_str(), ret);
660 SetBroken();
661 return;
662 }
663 }
664 }
665
666
667 // Open
668 fd_ = open_utf8(os_pathname_.c_str(),OPENFLAGS,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
669 if (fd_<0) {
670 //print_error("storage: file: Could not open");
671 dprintf("%s %s storage: file: Could not open %s\n", tintstr(), "0000000000000000000000000000000000000000",
672 os_pathname_.c_str());
673 SetBroken();
674 return;
675 }
676 }
677
~StorageFile()678 StorageFile::~StorageFile()
679 {
680 if (fd_>=0) {
681 close(fd_);
682 }
683 }
684
685