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