elock.h: add possibility to create recursive mutexes
[enigma2.git] / lib / base / rawfile.cpp
1 #include <cstdio>
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <lib/base/rawfile.h>
5 #include <lib/base/eerror.h>
6
7 eRawFile::eRawFile()
8 {
9         m_fd = -1;
10         m_file = 0;
11         m_splitsize = 0;
12         m_totallength = 0;
13         m_current_offset = 0;
14         m_base_offset = 0;
15         m_last_offset = 0;
16         m_nrfiles = 0;
17         m_current_file = 0;
18 }
19
20 eRawFile::~eRawFile()
21 {
22         close();
23 }
24
25 int eRawFile::open(const char *filename, int cached)
26 {
27         close();
28         m_cached = cached;
29         m_basename = filename;
30         scan();
31         m_current_offset = 0;
32         m_last_offset = 0;
33         if (!m_cached)
34         {
35                 m_fd = ::open(filename, O_RDONLY | O_LARGEFILE);
36                 return m_fd;
37         } else
38         {
39                 m_file = ::fopen64(filename, "rb");
40                 if (!m_file)
41                         return -1;
42                 return 0;
43         }
44 }
45
46 void eRawFile::setfd(int fd)
47 {
48         close();
49         m_cached = 0;
50         m_nrfiles = 1;
51         m_fd = fd;
52 }
53
54 off_t eRawFile::lseek(off_t offset, int whence)
55 {
56 //      eDebug("lseek: %lld, %d", offset, whence);
57                 /* if there is only one file, use the native lseek - the file could be growing! */
58         if (m_nrfiles < 2)
59         {
60                 if (!m_cached)
61                         return ::lseek(m_fd, offset, whence);
62                 else
63                 {
64                         ::fseeko(m_file, offset, whence);
65                         return ::ftello(m_file);
66                 }
67         }
68         switch (whence)
69         {
70         case SEEK_SET:
71                 m_current_offset = offset;
72                 break;
73         case SEEK_CUR:
74                 m_current_offset += offset;
75                 break;
76         case SEEK_END:
77                 m_current_offset = m_totallength + offset;
78                 break;
79         }
80
81         if (m_current_offset < 0)
82                 m_current_offset = 0;
83         return m_current_offset;
84 }
85
86 int eRawFile::close()
87 {
88         if (m_cached)
89         {
90                 if (!m_file)
91                         return -1;
92                 ::fclose(m_file);
93                 m_file = 0;
94                 return 0;
95         } else
96         {
97                 int ret = ::close(m_fd);
98                 m_fd = -1;
99                 return ret;
100         }
101 }
102
103 ssize_t eRawFile::read(void *buf, size_t count)
104 {
105 //      eDebug("read: %p, %d", buf, count);
106         switchOffset(m_current_offset);
107         
108         if (m_nrfiles >= 2)
109         {
110                 if (m_current_offset + count > m_totallength)
111                         count = m_totallength - m_current_offset;
112                 if (count < 0)
113                         return 0;
114         }
115         
116         int ret;
117         
118         if (!m_cached)
119                 ret = ::read(m_fd, buf, count);
120         else
121                 ret = ::fread(buf, 1, count, m_file);
122
123         if (ret > 0)
124                 m_current_offset = m_last_offset += ret;
125         return ret;
126 }
127
128 int eRawFile::valid()
129 {
130         if (!m_cached)
131                 return m_fd != -1;
132         else
133                 return !!m_file;
134 }
135
136 void eRawFile::scan()
137 {
138         m_nrfiles = 0;
139         m_totallength = 0;
140         while (m_nrfiles < 1000) /* .999 is the last possible */
141         {
142                 if (!m_cached)
143                 {
144                         int f = openFileUncached(m_nrfiles);
145                         if (f < 0)
146                                 break;
147                         if (!m_nrfiles)
148                                 m_splitsize = ::lseek(f, 0, SEEK_END);
149                         m_totallength += ::lseek(f, 0, SEEK_END);
150                         ::close(f);
151                 } else
152                 {
153                         FILE *f = openFileCached(m_nrfiles);
154                         if (!f)
155                                 break;
156                         ::fseeko(f, 0, SEEK_END);
157                         if (!m_nrfiles)
158                                 m_splitsize = ::ftello(f);
159                         m_totallength += ::ftello(f);
160                         ::fclose(f);
161                 }
162                 
163                 ++m_nrfiles;
164         }
165 //      eDebug("found %d files, splitsize: %llx, totallength: %llx", m_nrfiles, m_splitsize, m_totallength);
166 }
167
168 int eRawFile::switchOffset(off_t off)
169 {
170         if (m_splitsize)
171         {
172                 int filenr = off / m_splitsize;
173                 if (filenr >= m_nrfiles)
174                         filenr = m_nrfiles - 1;
175                 if (filenr != m_current_file)
176                 {       
177 //                      eDebug("-> %d", filenr);
178                         close();
179                         if (!m_cached)
180                                 m_fd = openFileUncached(filenr);
181                         else
182                                 m_file = openFileCached(filenr);
183                         m_last_offset = m_base_offset = m_splitsize * filenr;
184                         m_current_file = filenr;
185                 }
186         } else
187                 m_base_offset = 0;
188         
189         if (off != m_last_offset)
190         {
191                 if (!m_cached)
192                         m_last_offset = ::lseek(m_fd, off - m_base_offset, SEEK_SET) + m_base_offset;
193                 else
194                 {
195                         ::fseeko(m_file, off - m_base_offset, SEEK_SET);
196                         m_last_offset = ::ftello(m_file) + m_base_offset;
197                 }
198                 return m_last_offset;
199         } else
200         {
201                 return m_last_offset;
202         }
203 }
204
205 /* m_cached */
206 FILE *eRawFile::openFileCached(int nr)
207 {
208         std::string filename = m_basename;
209         if (nr)
210         {
211                 char suffix[5];
212                 snprintf(suffix, 5, ".%03d", nr);
213                 filename += suffix;
214         }
215         return ::fopen64(filename.c_str(), "rb");
216 }
217
218 /* !m_cached */
219 int eRawFile::openFileUncached(int nr)
220 {
221         std::string filename = m_basename;
222         if (nr)
223         {
224                 char suffix[5];
225                 snprintf(suffix, 5, ".%03d", nr);
226                 filename += suffix;
227         }
228         return ::open(filename.c_str(), O_RDONLY | O_LARGEFILE);
229 }
230
231 off_t eRawFile::length()
232 {
233         return m_totallength;
234 }