status_t Model::_SaveHistory(const BList& items) const { BFile file; status_t status = _OpenFile(&file, PREFS_FILE, B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE, B_USER_SETTINGS_DIRECTORY, NULL); if (status != B_OK) return status; status = file.Lock(); if (status != B_OK) return status; BMessage message; int32 count = items.CountItems(); for (int32 i = 0; i < count; i++) { BString* string = static_cast<BString*>(items.ItemAtFast(i)); if (message.AddString("string", string->String()) != B_OK) break; } status = message.Flatten(&file); file.SetSize(message.FlattenedSize()); file.Sync(); file.Unlock(); return status; }
bool Model::_LoadHistory(BList& items) const { BFile file; status_t status = _OpenFile(&file, PREFS_FILE); if (status != B_OK) return false; status = file.Lock(); if (status != B_OK) return false; BMessage message; status = message.Unflatten(&file); if (status != B_OK) return false; file.Unlock(); BString string; for (int32 x = 0; message.FindString("string", x, &string) == B_OK; x++) { BString* copy = new (nothrow) BString(string); if (copy == NULL || !items.AddItem(copy)) { delete copy; break; } } return true; }
status_t Model::LoadPrefs() { BFile file; status_t status = _OpenFile(&file, PREFS_FILE); if (status != B_OK) return status; status = file.Lock(); if (status != B_OK) return status; int32 value; if (file.ReadAttr("RecurseDirs", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0) fRecurseDirs = (value != 0); if (file.ReadAttr("RecurseLinks", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0) fRecurseLinks = (value != 0); if (file.ReadAttr("SkipDotDirs", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0) fSkipDotDirs = (value != 0); if (file.ReadAttr("CaseSensitive", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0) fCaseSensitive = (value != 0); if (file.ReadAttr("EscapeText", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0) fEscapeText = (value != 0); if (file.ReadAttr("TextOnly", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0) fTextOnly = (value != 0); if (file.ReadAttr("InvokePe", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0) fInvokePe = (value != 0); if (file.ReadAttr("ShowContents", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0) fShowContents = (value != 0); char buffer [B_PATH_NAME_LENGTH+1]; int32 length = file.ReadAttr("FilePanelPath", B_STRING_TYPE, 0, &buffer, sizeof(buffer)); if (length > 0) { buffer[length] = '\0'; fFilePanelPath = buffer; } file.ReadAttr("WindowFrame", B_RECT_TYPE, 0, &fFrame, sizeof(BRect)); if (file.ReadAttr("Encoding", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0) fEncoding = value; file.Unlock(); return B_OK; }
void BMailRemoteStorageProtocol::SyncMailbox(const char *mailbox) { BPath path(runner->Chain()->MetaData()->FindString("path")); path.Append(mailbox); BDirectory folder(path.Path()); BEntry entry; BFile snoodle; BString string; uint32 chain; bool append; while (folder.GetNextEntry(&entry) == B_OK) { if (!entry.IsFile()) continue; while (snoodle.SetTo(&entry,B_READ_WRITE) == B_BUSY) snooze(100); append = false; while (snoodle.Lock() != B_OK) snooze(100); snoodle.Unlock(); if (snoodle.ReadAttr("MAIL:chain",B_INT32_TYPE,0,&chain,sizeof(chain)) < B_OK) append = true; if (chain != runner->Chain()->ID()) append = true; if (snoodle.ReadAttrString("MAIL:unique_id",&string) < B_OK) append = true; BString folder(string), id(""); int32 j = string.FindLast('/'); if ((!append) && (j >= 0)) { folder.Truncate(j); string.CopyInto(id,j + 1,string.Length()); if (folder == mailbox) continue; } else { append = true; } if (append) AddMessage(mailbox,&snoodle,&id); //---We should check for partial messages here else CopyMessage(folder.String(),mailbox,&id); string = mailbox; string << '/' << id; /*snoodle.RemoveAttr("MAIL:unique_id"); snoodle.RemoveAttr("MAIL:chain");*/ chain = runner->Chain()->ID(); snoodle.WriteAttr("MAIL:chain",B_INT32_TYPE,0,&chain,sizeof(chain)); snoodle.WriteAttrString("MAIL:unique_id",&string); (*manifest) += string.String(); (*unique_ids) += string.String(); string = runner->Chain()->Name(); snoodle.WriteAttrString("MAIL:account",&string); } }
status_t Model::SavePrefs() { BFile file; status_t status = _OpenFile(&file, PREFS_FILE, B_CREATE_FILE | B_WRITE_ONLY); if (status != B_OK) return status; status = file.Lock(); if (status != B_OK) return status; int32 value = 2; file.WriteAttr("Version", B_INT32_TYPE, 0, &value, sizeof(int32)); value = fRecurseDirs ? 1 : 0; file.WriteAttr("RecurseDirs", B_INT32_TYPE, 0, &value, sizeof(int32)); value = fRecurseLinks ? 1 : 0; file.WriteAttr("RecurseLinks", B_INT32_TYPE, 0, &value, sizeof(int32)); value = fSkipDotDirs ? 1 : 0; file.WriteAttr("SkipDotDirs", B_INT32_TYPE, 0, &value, sizeof(int32)); value = fCaseSensitive ? 1 : 0; file.WriteAttr("CaseSensitive", B_INT32_TYPE, 0, &value, sizeof(int32)); value = fRegularExpression ? 1 : 0; file.WriteAttr("RegularExpression", B_INT32_TYPE, 0, &value, sizeof(int32)); value = fTextOnly ? 1 : 0; file.WriteAttr("TextOnly", B_INT32_TYPE, 0, &value, sizeof(int32)); value = fInvokeEditor ? 1 : 0; file.WriteAttr("InvokeEditor", B_INT32_TYPE, 0, &value, sizeof(int32)); file.WriteAttr("WindowFrame", B_RECT_TYPE, 0, &fFrame, sizeof(BRect)); file.WriteAttr("FilePanelPath", B_STRING_TYPE, 0, fFilePanelPath.String(), fFilePanelPath.Length() + 1); value = fShowLines ? 1 : 0; file.WriteAttr("ShowLines", B_INT32_TYPE, 0, &value, sizeof(int32)); file.WriteAttr("Encoding", B_INT32_TYPE, 0, &fEncoding, sizeof(int32)); file.Sync(); file.Unlock(); return B_OK; }
status_t MailInternal::WriteMessageFile(const BMessage& archive, const BPath& path, const char* name) { status_t ret = B_OK; BString leaf = name; leaf << ".tmp"; BEntry settings_entry; BFile tmpfile; bigtime_t now = system_time(); create_directory(path.Path(), 0777); { BDirectory account_dir(path.Path()); ret = account_dir.InitCheck(); if (ret != B_OK) { fprintf(stderr, "Couldn't open '%s': %s\n", path.Path(), strerror(ret)); return ret; } // get an entry for the tempfile // Get it here so that failure doesn't create any problems ret = settings_entry.SetTo(&account_dir,leaf.String()); if (ret != B_OK) { fprintf(stderr, "Couldn't create an entry for '%s/%s': %s\n", path.Path(), leaf.String(), strerror(ret)); return ret; } } // // Save to a temporary file // // Our goal is to write to a tempfile and then use 'rename' to // link that file into place once it contains valid contents. // Given the filesystem's guarantee of atomic "rename" oper- // ations this will guarantee that any non-temp files in the // config directory are valid configuration files. // // Ideally, we would be able to do the following: // BFile tmpfile(&account_dir, "tmpfile", B_WRITE_ONLY|B_CREATE_FILE); // // ... // tmpfile.Relink(&account_dir,"realfile"); // But this doesn't work because there is no way in the API // to link based on file descriptor. (There should be, for // exactly this reason, and I see no reason that it can not // be added to the API, but as it is not present now so we'll // have to deal.) It has to be file-descriptor based because // (a) all a BFile knows is its node/FD and (b) the file may // be unlinked at any time, at which point renaming the entry // to clobber the "realfile" will result in an invalid con- // figuration file being created. // // We can't count on not clobbering the tempfile to gain // exclusivity because, if the system crashes between when // we create the tempfile an when we rename it, we will have // a zombie tempfile that will prevent us from doing any more // saves. // // What we can do is: // // Create or open the tempfile // // At this point no one will *clobber* the file, but // // others may open it // Lock the tempfile // // At this point, no one else may open it and we have // // exclusive access to it. Because of the above, we // // know that our entry is still valid // // Truncate the tempfile // Write settings // Sync // Rename to the realfile // // this does not affect the lock, but now open- // // ing the realfile will fail with B_BUSY // Unlock // // If this code is the only code that changes these files, // then we are guaranteed that all realfiles will be valid // settings files. I think that's the best we can do unless // we get the Relink() api. An implementation of the above // follows. // // Create or open ret = B_TIMED_OUT; while (system_time() - now < timeout) //-ATT-no timeout arg. Setting by #define { ret = tmpfile.SetTo(&settings_entry, B_WRITE_ONLY | B_CREATE_FILE); if (ret != B_BUSY) break; // wait 1/100th second snooze((bigtime_t)1e4); } if (ret != B_OK) { fprintf(stderr, "Couldn't open '%s/%s' within the timeout period (%fs): %s\n", path.Path(), leaf.String(), (float)timeout/1e6, strerror(ret)); return ret==B_BUSY? B_TIMED_OUT:ret; } // lock ret = B_TIMED_OUT; while (system_time() - now < timeout) { ret = tmpfile.Lock(); //-ATT-changed account_file to tmpfile. Is that allowed? if (ret != B_BUSY) break; // wait 1/100th second snooze((bigtime_t)1e4); } if (ret != B_OK) { fprintf(stderr, "Couldn't lock '%s/%s' in within the timeout period (%fs): %s\n", path.Path(), leaf.String(), (float)timeout/1e6, strerror(ret)); // Can't remove it here, since it might be someone else's. // Leaving a zombie shouldn't cause any problems tho so // that's OK. return ret==B_BUSY? B_TIMED_OUT:ret; } // truncate tmpfile.SetSize(0); // write ret = archive.Flatten(&tmpfile); if (ret != B_OK) { fprintf(stderr, "Couldn't flatten settings to '%s/%s': %s\n", path.Path(), leaf.String(), strerror(ret)); return ret; } // ensure it's actually writen ret = tmpfile.Sync(); if (ret != B_OK) { fprintf(stderr, "Couldn't sync settings to '%s/%s': %s\n", path.Path(), leaf.String(), strerror(ret)); return ret; } // clobber old settings ret = settings_entry.Rename(name,true); if (ret != B_OK) { fprintf(stderr, "Couldn't clobber old settings '%s/%s': %s\n", path.Path(), name, strerror(ret)); return ret; } return B_OK; }