~ubuntu-branches/debian/squeeze/stella/squeeze

« back to all changes in this revision

Viewing changes to src/unix/FSNodePOSIX.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Stephen Kitt
  • Date: 2010-07-12 23:49:36 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20100712234936-juawrr3etzhr2qpv
Tags: 3.1.2-1
* New maintainer (closes: #532039).
* New upstream version (closes: #461121):
  - includes launcher (closes: #396058).
* Fix the reference to the X Window System in the description (closes:
  #411815).
* Move to main, DFSG-free ROMs are available (see README.Debian).
* Enhance the package description.
* Drop the libslang2-dev dependency (closes: #560274).
* Remove the Encoding entry from stella.desktop.
* Avoid ignoring errors when cleaning.
* Add ${misc:Depends} to the package dependencies.
* Provide a doc-base file to install the documentation using doc-base.
* Switch to debhelper 7 with a simplified rules file.
* Use autotools-dev to provide updated configuration files.
* Update to Standards-Version 3.9.0:
  - Move to menu section Applications/Emulators.
  - Move the homepage declaration.
* Re-write the manpage.

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
//  SS  SS   tt   ee      ll   ll  aa  aa
9
9
//   SSSS     ttt  eeeee llll llll  aaaaa
10
10
//
11
 
// Copyright (c) 1995-2008 by Bradford W. Mott and the Stella team
 
11
// Copyright (c) 1995-2010 by Bradford W. Mott, Stephen Anthony
 
12
// and the Stella Team
12
13
//
13
 
// See the file "license" for information on usage and redistribution of
 
14
// See the file "License.txt" for information on usage and redistribution of
14
15
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
15
16
//
16
 
// $Id: FSNodePOSIX.cxx,v 1.14 2008/03/14 23:52:17 stephena Exp $
 
17
// $Id: FSNodePOSIX.cxx 2001 2010-04-10 21:37:23Z stephena $
17
18
//
18
19
//   Based on code from ScummVM - Scumm Interpreter
19
20
//   Copyright (C) 2002-2004 The ScummVM project
29
30
#include <sys/stat.h>
30
31
#include <dirent.h>
31
32
 
32
 
#include <stdio.h>
 
33
#include <cassert>
 
34
#include <cstdio>
 
35
#include <cstring>
33
36
#include <unistd.h>
34
37
 
35
38
#include <sstream>
36
39
 
37
40
/*
38
41
 * Implementation of the Stella file system API based on POSIX (for Linux and OSX)
 
42
 *
 
43
 * Parts of this class are documented in the base interface class, AbstractFilesystemNode.
39
44
 */
40
 
 
41
45
class POSIXFilesystemNode : public AbstractFilesystemNode
42
46
{
43
47
  public:
 
48
    /**
 
49
     * Creates a POSIXFilesystemNode with the root node as path.
 
50
     */
44
51
    POSIXFilesystemNode();
45
 
    POSIXFilesystemNode(const string& path);
46
 
    POSIXFilesystemNode(const POSIXFilesystemNode* node);
47
 
 
48
 
    virtual string displayName() const { return _displayName; }
49
 
    virtual bool isValid() const { return _isValid; }
 
52
 
 
53
    /**
 
54
     * Creates a POSIXFilesystemNode for a given path.
 
55
     *
 
56
     * @param path String with the path the new node should point to.
 
57
     * @param verify true if the isValid and isDirectory flags should be verified during the construction.
 
58
     */
 
59
    POSIXFilesystemNode(const string& path, bool verify);
 
60
 
 
61
    virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; }
 
62
    virtual string getDisplayName() const { return _displayName; }
 
63
    virtual string getName() const   { return _displayName; }
 
64
    virtual string getPath() const   { return _path; }
 
65
    virtual string getRelativePath() const;
50
66
    virtual bool isDirectory() const { return _isDirectory; }
51
 
    virtual string path() const { return _path; }
 
67
    virtual bool isReadable() const  { return access(_path.c_str(), R_OK) == 0; }
 
68
    virtual bool isWritable() const  { return access(_path.c_str(), W_OK) == 0; }
52
69
 
53
 
    virtual FSList listDir(ListMode mode = kListDirectoriesOnly) const;
54
 
    virtual AbstractFilesystemNode* parent() const;
 
70
    virtual bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const;
 
71
    virtual AbstractFilesystemNode* getParent() const;
55
72
 
56
73
  protected:
57
74
    string _displayName;
 
75
    string _path;
58
76
    bool _isDirectory;
59
77
    bool _isValid;
60
 
    string _path;
 
78
 
 
79
  private:
 
80
    /**
 
81
     * Tests and sets the _isValid and _isDirectory flags, using the stat() function.
 
82
     */
 
83
    virtual void setFlags();
61
84
};
62
85
 
 
86
/**
 
87
 * Returns the last component of a given path.
 
88
 *
 
89
 * Examples:
 
90
 *                      /foo/bar.txt would return /bar.txt
 
91
 *                      /foo/bar/    would return /bar/
 
92
 *
 
93
 * @param str String containing the path.
 
94
 * @return Pointer to the first char of the last component inside str.
 
95
 */
63
96
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
64
 
static const char* lastPathComponent(const string& str)
 
97
const char* lastPathComponent(const string& str)
65
98
{
 
99
  if(str.empty())
 
100
    return "";
 
101
 
66
102
  const char *start = str.c_str();
67
103
  const char *cur = start + str.size() - 2;
68
 
        
69
 
  while (cur > start && *cur != '/')
 
104
 
 
105
  while (cur >= start && *cur != '/')
70
106
    --cur;
71
 
        
72
 
  return cur+1;
73
 
}
74
 
 
75
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
76
 
static string validatePath(const string& p)
77
 
{
78
 
  string path = p;
79
 
  if(p.size() <= 0 || p[0] != '/')
80
 
    path = "/";
81
 
 
82
 
  return path;
83
 
}
84
 
 
85
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
86
 
AbstractFilesystemNode* FilesystemNode::getRoot()
87
 
{
88
 
  return new POSIXFilesystemNode();
89
 
}
90
 
 
91
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
92
 
AbstractFilesystemNode* FilesystemNode::getNodeForPath(const string& path)
93
 
{
94
 
  return new POSIXFilesystemNode(validatePath(path));
 
107
 
 
108
  return cur + 1;
 
109
}
 
110
 
 
111
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
112
void POSIXFilesystemNode::setFlags()
 
113
{
 
114
  struct stat st;
 
115
 
 
116
  _isValid = (0 == stat(_path.c_str(), &st));
 
117
  _isDirectory = _isValid ? S_ISDIR(st.st_mode) : false;
95
118
}
96
119
 
97
120
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
98
121
POSIXFilesystemNode::POSIXFilesystemNode()
99
122
{
100
 
  char buf[MAXPATHLEN];
101
 
  getcwd(buf, MAXPATHLEN);
102
 
 
103
 
  _path = buf;
104
 
  _displayName = lastPathComponent(_path);
105
 
  _path += '/';
 
123
  // The root dir.
 
124
  _path = "/";
 
125
  _displayName = _path;
106
126
  _isValid = true;
107
127
  _isDirectory = true;
108
128
}
109
129
 
110
130
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
111
 
POSIXFilesystemNode::POSIXFilesystemNode(const string& p)
112
 
{
113
 
  string path = validatePath(p);
114
 
 
115
 
  Int32 len = 0, offset = path.size();
116
 
  struct stat st;
117
 
 
118
 
  _path = path;
119
 
 
120
 
  // Extract last component from path
121
 
  const char *str = path.c_str();
122
 
  while (offset > 0 && str[offset-1] == '/')
123
 
    offset--;
124
 
  while (offset > 0 && str[offset-1] != '/')
125
 
  {
126
 
    len++;
127
 
    offset--;
128
 
  }
129
 
  _displayName = string(str + offset, len);
130
 
 
131
 
  // Check whether it is a directory, and whether the file actually exists
132
 
  _isValid = (0 == stat(_path.c_str(), &st));
133
 
  _isDirectory = S_ISDIR(st.st_mode);
134
 
}
135
 
 
136
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
137
 
POSIXFilesystemNode::POSIXFilesystemNode(const POSIXFilesystemNode* node)
138
 
{
139
 
  _displayName = node->_displayName;
140
 
  _isValid = node->_isValid;
141
 
  _isDirectory = node->_isDirectory;
142
 
  _path = node->_path;
143
 
}
144
 
 
145
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
146
 
FSList POSIXFilesystemNode::listDir(ListMode mode) const
147
 
{
 
131
POSIXFilesystemNode::POSIXFilesystemNode(const string& p, bool verify)
 
132
{
 
133
  // Expand "~/" to the value of the HOME env variable
 
134
  if ( p.length() >= 2 && p[0] == '~' && p[1] == '/')
 
135
  {
 
136
    const char *home = getenv("HOME");
 
137
    if (home != NULL && strlen(home) < MAXPATHLEN)
 
138
    {
 
139
      _path = home;
 
140
      // Skip over the tilde.  We know that p contains at least
 
141
      // two chars, so this is safe:
 
142
      _path += p.c_str() + 1;
 
143
    }
 
144
  }
 
145
  // Expand "./" to the current directory
 
146
  else if ( p.length() >= 2 && p[0] == '.' && p[1] == '/')
 
147
  {
 
148
    char buf[MAXPATHLEN];
 
149
    char* ret = getcwd(buf, MAXPATHLEN);
 
150
    if (ret == buf)
 
151
    {
 
152
      _path = buf;
 
153
      // Skip over the tilda.  We know that p contains at least
 
154
      // two chars, so this is safe:
 
155
      _path += p.c_str() + 1;
 
156
    }
 
157
  }
 
158
  else
 
159
    _path = p;
 
160
 
 
161
  _displayName = lastPathComponent(_path);
 
162
 
 
163
  if (verify)
 
164
    setFlags();
 
165
}
 
166
 
 
167
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
168
string POSIXFilesystemNode::getRelativePath() const
 
169
{
 
170
  // If the path starts with the home directory, replace it with '~'
 
171
  const char* home = getenv("HOME");
 
172
  if(home != NULL)
 
173
  {
 
174
    int len = strlen(home);
 
175
    if(strncmp(_path.c_str(), home, len) == 0)
 
176
    {
 
177
      string path = "~";
 
178
      const char* offset = _path.c_str() + len;
 
179
      if(*offset != '/') path += "/";
 
180
      path += offset;
 
181
      return path;
 
182
    }
 
183
  }
 
184
  return _path;
 
185
}
 
186
 
 
187
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
188
bool POSIXFilesystemNode::getChildren(AbstractFSList& myList, ListMode mode,
 
189
                                      bool hidden) const
 
190
{
 
191
  assert(_isDirectory);
 
192
 
148
193
  DIR *dirp = opendir(_path.c_str());
149
 
  struct stat st;
150
 
 
151
194
  struct dirent *dp;
152
 
  FSList myList;
153
195
 
154
196
  if (dirp == NULL)
155
 
    return myList;
 
197
    return false;
156
198
 
157
 
  // ... loop over dir entries using readdir
 
199
  // loop over dir entries using readdir
158
200
  while ((dp = readdir(dirp)) != NULL)
159
201
  {
160
 
    // Skip 'invisible' files
161
 
    if (dp->d_name[0] == '.')
162
 
      continue;
163
 
 
164
 
    POSIXFilesystemNode entry;
165
 
    entry._displayName = dp->d_name;
166
 
    entry._path = _path;
167
 
    if (entry._path.length() > 0 && entry._path[entry._path.length()-1] != '/')
168
 
      entry._path += '/';
169
 
    entry._path += dp->d_name;
170
 
 
171
 
    if (stat(entry._path.c_str(), &st))
172
 
      continue;
173
 
    entry._isDirectory = S_ISDIR(st.st_mode);
 
202
    // Skip 'invisible' files if necessary
 
203
    if (dp->d_name[0] == '.' && !hidden)
 
204
      continue;
 
205
 
 
206
    // Skip '.' and '..' to avoid cycles
 
207
    if ((dp->d_name[0] == '.' && dp->d_name[1] == 0) || (dp->d_name[0] == '.' && dp->d_name[1] == '.'))
 
208
      continue;
 
209
 
 
210
    string newPath(_path);
 
211
    if (newPath.length() > 0 && newPath[newPath.length()-1] != '/')
 
212
      newPath += '/';
 
213
    newPath += dp->d_name;
 
214
 
 
215
    POSIXFilesystemNode entry(newPath, false);
 
216
 
 
217
#if defined(SYSTEM_NOT_SUPPORTING_D_TYPE)
 
218
    /* TODO: d_type is not part of POSIX, so it might not be supported
 
219
     * on some of our targets. For those systems where it isn't supported,
 
220
     * add this #elif case, which tries to use stat() instead.
 
221
     *
 
222
     * The d_type method is used to avoid costly recurrent stat() calls in big
 
223
     * directories.
 
224
     */
 
225
    entry.setFlags();
 
226
#else
 
227
    if (dp->d_type == DT_UNKNOWN)
 
228
    {
 
229
      // Fall back to stat()
 
230
      entry.setFlags();
 
231
    }
 
232
    else
 
233
    {
 
234
      entry._isValid = (dp->d_type == DT_DIR) || (dp->d_type == DT_REG) || (dp->d_type == DT_LNK);
 
235
      if (dp->d_type == DT_LNK)
 
236
      {
 
237
        struct stat st;
 
238
        if (stat(entry._path.c_str(), &st) == 0)
 
239
          entry._isDirectory = S_ISDIR(st.st_mode);
 
240
        else
 
241
          entry._isDirectory = false;
 
242
      }
 
243
      else
 
244
        entry._isDirectory = (dp->d_type == DT_DIR);
 
245
    }
 
246
#endif
 
247
 
 
248
    // Skip files that are invalid for some reason (e.g. because we couldn't
 
249
    // properly stat them).
 
250
    if (!entry._isValid)
 
251
      continue;
174
252
 
175
253
    // Honor the chosen mode
176
 
    if ((mode == kListFilesOnly && entry._isDirectory) ||
177
 
        (mode == kListDirectoriesOnly && !entry._isDirectory))
 
254
    if ((mode == FilesystemNode::kListFilesOnly && entry._isDirectory) ||
 
255
        (mode == FilesystemNode::kListDirectoriesOnly && !entry._isDirectory))
178
256
      continue;
179
257
 
180
258
    if (entry._isDirectory)
181
259
      entry._path += "/";
182
260
 
183
 
    myList.push_back(wrap(new POSIXFilesystemNode(&entry)));
 
261
    myList.push_back(new POSIXFilesystemNode(entry));
184
262
  }
185
263
  closedir(dirp);
186
264
 
187
 
  return myList;
 
265
  return true;
188
266
}
189
267
 
190
268
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
191
 
AbstractFilesystemNode *POSIXFilesystemNode::parent() const
 
269
AbstractFilesystemNode* POSIXFilesystemNode::getParent() const
192
270
{
193
271
  if (_path == "/")
194
272
    return 0;
195
273
 
196
 
  POSIXFilesystemNode* p = new POSIXFilesystemNode();
197
274
  const char *start = _path.c_str();
198
275
  const char *end = lastPathComponent(_path);
199
276
 
200
 
  p->_path = string(start, end - start);
201
 
  p->_displayName = lastPathComponent(p->_path);
202
 
 
203
 
  p->_isValid = true;
204
 
  p->_isDirectory = true;
205
 
 
206
 
  return p;
207
 
}
208
 
 
209
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
210
 
bool AbstractFilesystemNode::fileExists(const string& path)
211
 
{
212
 
  struct stat st;
213
 
  if(stat(path.c_str(), &st) != 0)
214
 
    return false;
215
 
 
216
 
  return S_ISREG(st.st_mode);
217
 
}
218
 
 
219
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
220
 
bool AbstractFilesystemNode::dirExists(const string& path)
221
 
{
222
 
  struct stat st;
223
 
  if(stat(path.c_str(), &st) != 0)
224
 
    return false;
225
 
 
226
 
  return S_ISDIR(st.st_mode);
 
277
  return new POSIXFilesystemNode(string(start, end - start), true);
 
278
}
 
279
 
 
280
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
281
AbstractFilesystemNode* AbstractFilesystemNode::makeRootFileNode()
 
282
{
 
283
  return new POSIXFilesystemNode();
 
284
}
 
285
 
 
286
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
287
AbstractFilesystemNode* AbstractFilesystemNode::makeCurrentDirectoryFileNode()
 
288
{
 
289
  return new POSIXFilesystemNode("./", true);
 
290
}
 
291
 
 
292
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
293
AbstractFilesystemNode* AbstractFilesystemNode::makeHomeDirectoryFileNode()
 
294
{
 
295
  return new POSIXFilesystemNode("~/", true);
 
296
}
 
297
 
 
298
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
299
AbstractFilesystemNode* AbstractFilesystemNode::makeFileNodePath(const string& path)
 
300
{
 
301
  return new POSIXFilesystemNode(path, true);
227
302
}
228
303
 
229
304
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -