00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <stdio.h>
00025 #include <errno.h>
00026 #include <assert.h>
00027
00028 #include "fileproperty.hh"
00029
00030 #ifndef S_ISREG
00031 #define S_ISREG(x) (x & _S_IFREG)
00032 #endif
00033
00034
00035 FileProperty::FileProperty(MetaObject* superobject)
00036 : MetaObject(superobject), Property(superobject), LocalProperty(superobject), filehandle(0)
00037 {
00038 }
00039
00040 FileProperty::FileProperty(MetaObject* superobject, const string& file_name, const string& datatype)
00041 : MetaObject(superobject), Property(superobject), LocalProperty(superobject, "", datatype), filehandle(0), filename(file_name)
00042 {
00043 setFileBackend(file_name);
00044 }
00045
00046 FileProperty::~FileProperty()
00047 {
00048 if(filehandle) fclose(filehandle);
00049 }
00050
00051 void FileProperty::registerExtenders()
00052 {
00053 static bool done = false;
00054 if(! done) {
00055 LocalSite::addLocalObjectExtension(typeid(FileProperty).name(),
00056 &FileProperty::new_FileProperty);
00057 LocalSite::addLocalObjectExtension("property:property.file",
00058 &FileProperty::new_FileProperty);
00059 done = true;
00060 }
00061 }
00062
00063
00064 MetaObject* FileProperty::new_FileProperty(MetaObject* superobject, const string& type)
00065 {
00066 return new FileProperty(superobject);
00067 }
00068
00069 void FileProperty::checkOpenFile() throw (FileAccessError)
00070 {
00071 if(! filehandle) {
00072 if(! (filehandle=fopen(filename.c_str(), "r+b"))) {
00073 if(errno == EACCES) {
00074 if(! (filehandle=fopen(filename.c_str(), "rb"))) {
00075 throw FileAccessError(string(strerror(errno)) + " " + filename);
00076 }
00077 readonly = true;
00078 } else throw FileAccessError(string(strerror(errno)) + " " + filename);
00079 } else readonly = false;
00080 fstat(fileno(filehandle), &status);
00081 }
00082 struct stat curstat;
00083
00084 fstat(fileno(filehandle), &curstat);
00085
00086
00087 if(curstat.st_mtime > status.st_mtime) {
00088 fclose(filehandle);
00089 filehandle = 0;
00090 if(! (filehandle=fopen(filename.c_str(), "r+b"))) {
00091 throw FileAccessError(string(strerror(errno)) + " " + filename);
00092 }
00093 fstat(fileno(filehandle), &status);
00094 string s;
00095 readRaw(s, 0, getRawLength());
00096
00097 vRef<PropertyEvent> event = new PropertyEvent(
00098 PropertyEvent::PropertyReplace,
00099 *this, *this,
00100 s, getDataType(),
00101 false);
00102
00103 for(PropertyListenerMap::iterator i = propertyListeners.begin();
00104 i != propertyListeners.end();
00105 i++) {
00106 (*i).second->notifyPropertyChange(*event);
00107 }
00108
00109 }
00110 }
00111
00112 void FileProperty::setFileBackend(const string& file_name, const string& data_type) throw(FileAccessError)
00113 {
00114 if(filehandle) fclose(filehandle);
00115 filehandle=0;
00116 filename = file_name;
00117 raw_datatype = data_type;
00118
00119 struct stat curstat;
00120 if(stat(file_name.c_str(), &curstat) != 0
00121 || ! S_ISREG(curstat.st_mode))
00122 {
00123 throw FileAccessError("No such file " + file_name);
00124 }
00125 }
00126
00127 string FileProperty::getFileBackend()
00128 {
00129 return filename;
00130 }
00131
00132 int FileProperty::getRawLength() throw(FileAccessError)
00133 {
00134 checkOpenFile();
00135 fseek(filehandle, 0, SEEK_END);
00136 return ftell(filehandle);
00137 }
00138
00139 void FileProperty::readRaw(string& target, int start, int length) throw(FileAccessError)
00140 {
00141 checkOpenFile();
00142 if(length < 0)
00143 length = getRawLength() - (0 - (length + 1));
00144 if(start < 0) start = getRawLength() + start + 1;
00145 if(start > getRawLength()) { target = ""; return; }
00146 char* b = (char*)malloc(length);
00147 fseek(filehandle, start, SEEK_SET);
00148 length = fread(b, 1, length, filehandle);
00149 target = string(b, length);
00150 free(b);
00151 }
00152
00153 void FileProperty::read(string& target, int start, int length) throw(FileAccessError)
00154 {
00155
00156
00157 readRaw(target, start, length);
00158 datatype = TypeChain::decode(target, getRawDataType());
00159 data_length = target.size();
00160 }
00161
00162
00163
00164
00165 void FileProperty::write(int start, const string& newdata) throw(FileAccessError)
00166 {
00167 checkOpenFile();
00168 if(! readonly) {
00169 fseek(filehandle, start, SEEK_SET);
00170 fwrite(newdata.c_str(), newdata.size(), 1, filehandle);
00171 fstat(fileno(filehandle), &status);
00172 LocalProperty::write(0, "");
00173 } else {
00174 LOG("fileproperty", 2, "Tried to write to a read-only file " << filename);
00175 }
00176 }
00177
00178 void FileProperty::replace(const string& newdata, const string& newtype) throw(FileAccessError)
00179 {
00180 if(filehandle) fclose(filehandle);
00181 filehandle=0;
00182
00183 if(! (filehandle=fopen(filename.c_str(), "w+b"))) {
00184 if(errno == EACCES) {
00185 if(! (filehandle=fopen(filename.c_str(), "rb"))) {
00186 throw FileAccessError(string(strerror(errno)) + " " + filename);
00187 }
00188 readonly = true;
00189 LOG("fileproperty", 2, "Tried to replace a read-only file " << filename);
00190 }
00191 } else readonly = false;
00192 if(! readonly) {
00193 fstat(fileno(filehandle), &status);
00194 write(0, newdata);
00195
00196 Property::replace("", newtype);
00197
00198 vRef<PropertyEvent> event = new PropertyEvent(
00199 PropertyEvent::PropertyReplace,
00200 *this, *this,
00201 newdata, newtype,
00202 false);
00203
00204 for(PropertyListenerMap::iterator i = propertyListeners.begin(); i != propertyListeners.end(); i++) {
00205 (*i).second->notifyPropertyChange(*event);
00206 }
00207 }
00208 }
00209