Trim the include tree.
[ardour.git] / libs / pbd / filesystem.cc
1 /*
2         Copyright (C) 2007 Tim Mayberry 
3
4         This program is free software; you can redistribute it and/or modify
5         it under the terms of the GNU General Public License as published by
6         the Free Software Foundation; either version 2 of the License, or
7         (at your option) any later version.
8
9         This program is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12         GNU General Public License for more details.
13
14         You should have received a copy of the GNU General Public License
15         along with this program; if not, write to the Free Software
16         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <sys/stat.h>
20
21 #include <glib.h>
22 #include <glib/gstdio.h>
23
24 #include <cerrno>
25 #include <fstream>
26
27 #include <glibmm/fileutils.h>
28 #include <glibmm/miscutils.h>
29
30 #include "pbd/filesystem.h"
31 #include "pbd/error.h"
32 #include "pbd/compose.h"
33
34 #include "i18n.h"
35
36 using namespace std;
37
38 namespace PBD {
39
40 namespace sys {
41         
42 path&
43 path::operator/=(const path& rhs)
44 {
45         m_path = Glib::build_filename(m_path, rhs.m_path);
46         return *this;
47 }
48
49 path&
50 path::operator/=(const string& rhs)
51 {
52         m_path = Glib::build_filename(m_path, rhs);
53         return *this;
54 }
55
56 path&
57 path::operator/=(const char* rhs)
58 {
59         m_path = Glib::build_filename(m_path, rhs);
60         return *this;
61 }
62
63 string
64 path::leaf () const
65 {
66         return Glib::path_get_basename(m_path);
67 }
68
69 path
70 path::branch_path () const
71 {
72         string dir = Glib::path_get_dirname (m_path);
73
74         /*
75          * glib returns "." to signify that the path
76          * has no directory components(branch path)
77          * whereas boost::filesystem returns an empty
78          * string
79          */
80         if(dir == ".")
81         {
82                 return "";
83         }
84         return dir;
85 }
86
87 bool
88 exists (const path & p)
89 {
90         return Glib::file_test (p.to_string(), Glib::FILE_TEST_EXISTS);
91 }
92
93 bool
94 exists_and_writable (const path & p)
95 {
96         /* writable() really reflects the whole folder, but if for any
97            reason the session state file can't be written to, still
98            make us unwritable.
99         */
100
101         struct stat statbuf;
102
103         if (g_stat (p.to_string().c_str(), &statbuf) != 0) {
104                 /* doesn't exist - not writable */
105                 return false;
106         } else {
107                 if (!(statbuf.st_mode & S_IWUSR)) {
108                         /* exists and is not writable */
109                         return false;
110                 }
111         }
112
113         return true;
114 }
115
116
117 bool
118 is_directory (const path & p)
119 {
120         return Glib::file_test (p.to_string(), Glib::FILE_TEST_IS_DIR);
121 }
122
123 bool
124 create_directory(const path & p)
125 {
126         if(is_directory(p)) return false;
127
128         int error = g_mkdir (p.to_string().c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
129
130         if(error == -1)
131         {
132                 throw filesystem_error(g_strerror(errno), errno);
133         }
134         return true;
135 }
136
137 bool
138 create_directories(const path & p)
139 {
140         if(is_directory(p)) return false;
141
142         int error = g_mkdir_with_parents (p.to_string().c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
143
144         if(error == -1)
145         {
146                 throw filesystem_error(g_strerror(errno), errno);
147         }
148         return true;
149 }
150
151 bool
152 remove(const path & p)
153 {
154         if(!exists(p)) return false;
155
156         int error = g_unlink (p.to_string().c_str());
157
158         if(error == -1)
159         {
160                 throw filesystem_error(g_strerror(errno), errno);
161         }
162         return true;
163 }
164
165 void
166 rename (const path & from_path, const path & to_path)
167 {
168         // g_rename is a macro that evaluates to ::rename on
169         // POSIX systems, without the global namespace qualifier
170         // it would evaluate to a recursive call(if it compiled)
171         if ( ::g_rename( from_path.to_string().c_str(),
172                                 to_path.to_string().c_str() ) == -1 )
173         {
174                 throw filesystem_error(g_strerror(errno), errno);
175         }
176 }
177
178 // XXX character encoding.
179 void
180 copy_file(const path & from_path, const path & to_path)
181 {
182         std::ifstream in(from_path.to_string().c_str());
183         std::ofstream out(to_path.to_string().c_str());
184         
185         if (!in || !out) {
186                 throw filesystem_error(string_compose(_("Could not open files %1 and %2 for copying"),
187                                         from_path.to_string(), to_path.to_string()));
188         }
189         
190         out << in.rdbuf();
191         
192         if (!in || !out) {
193                 remove (to_path);
194                 throw filesystem_error(string_compose(_("Could not copy existing file %1 to %2"),
195                                         from_path.to_string(), to_path.to_string()));
196         }
197 }
198
199 string
200 basename (const path & p)
201 {
202         string base(p.leaf());
203
204         string::size_type n = base.rfind ('.');
205
206         return base.substr (0, n);
207 }
208
209 string
210 extension (const path & p)
211 {
212         string base(p.leaf());
213
214         string::size_type n = base.rfind ('.');
215
216         if (n != string::npos)
217         {
218                 return base.substr(n);
219         }
220
221         return string();
222
223 }
224
225 } // namespace sys
226
227 } // namespace PBD