remove stupid symlink stuff
[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 <giomm/file.h>
25
26 #include <cerrno>
27 #include <fstream>
28
29 #include <glibmm/fileutils.h>
30 #include <glibmm/miscutils.h>
31
32 #include "pbd/filesystem.h"
33 #include "pbd/error.h"
34 #include "pbd/compose.h"
35
36 #include "i18n.h"
37
38 using namespace std;
39
40 namespace PBD {
41
42 namespace sys {
43         
44 path&
45 path::operator/=(const path& rhs)
46 {
47         m_path = Glib::build_filename(m_path, rhs.m_path);
48         return *this;
49 }
50
51 path&
52 path::operator/=(const string& rhs)
53 {
54         m_path = Glib::build_filename(m_path, rhs);
55         return *this;
56 }
57
58 path&
59 path::operator/=(const char* rhs)
60 {
61         m_path = Glib::build_filename(m_path, rhs);
62         return *this;
63 }
64
65 string
66 path::leaf () const
67 {
68         return Glib::path_get_basename(m_path);
69 }
70
71 path
72 path::branch_path () const
73 {
74         string dir = Glib::path_get_dirname (m_path);
75
76         /*
77          * glib returns "." to signify that the path
78          * has no directory components(branch path)
79          * whereas boost::filesystem returns an empty
80          * string
81          */
82         if(dir == ".")
83         {
84                 return "";
85         }
86         return dir;
87 }
88
89 bool
90 exists (const path & p)
91 {
92         return Glib::file_test (p.to_string(), Glib::FILE_TEST_EXISTS);
93 }
94
95 bool
96 exists_and_writable (const path & p)
97 {
98         /* writable() really reflects the whole folder, but if for any
99            reason the session state file can't be written to, still
100            make us unwritable.
101         */
102
103         struct stat statbuf;
104
105         if (g_stat (p.to_string().c_str(), &statbuf) != 0) {
106                 /* doesn't exist - not writable */
107                 return false;
108         } else {
109                 if (!(statbuf.st_mode & S_IWUSR)) {
110                         /* exists and is not writable */
111                         return false;
112                 }
113         }
114
115         return true;
116 }
117
118
119 bool
120 is_directory (const path & p)
121 {
122         return Glib::file_test (p.to_string(), Glib::FILE_TEST_IS_DIR);
123 }
124
125 bool
126 create_directory(const path & p)
127 {
128         if(is_directory(p)) return false;
129
130         int error = g_mkdir (p.to_string().c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
131
132         if(error == -1)
133         {
134                 throw filesystem_error(g_strerror(errno), errno);
135         }
136         return true;
137 }
138
139 bool
140 create_directories(const path & p)
141 {
142         if(is_directory(p)) return false;
143
144         int error = g_mkdir_with_parents (p.to_string().c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
145
146         if(error == -1)
147         {
148                 throw filesystem_error(g_strerror(errno), errno);
149         }
150         return true;
151 }
152
153 bool
154 remove(const path & p)
155 {
156         if(!exists(p)) return false;
157
158         int error = g_unlink (p.to_string().c_str());
159
160         if(error == -1)
161         {
162                 throw filesystem_error(g_strerror(errno), errno);
163         }
164         return true;
165 }
166
167 void
168 rename (const path & from_path, const path & to_path)
169 {
170         // g_rename is a macro that evaluates to ::rename on
171         // POSIX systems, without the global namespace qualifier
172         // it would evaluate to a recursive call(if it compiled)
173         if ( ::g_rename( from_path.to_string().c_str(),
174                                 to_path.to_string().c_str() ) == -1 )
175         {
176                 throw filesystem_error(g_strerror(errno), errno);
177         }
178 }
179
180 // XXX character encoding.
181 void
182 copy_file(const path & from_path, const path & to_path)
183 {
184         std::ifstream in(from_path.to_string().c_str());
185         std::ofstream out(to_path.to_string().c_str());
186         
187         if (!in || !out) {
188                 throw filesystem_error(string_compose(_("Could not open files %1 and %2 for copying"),
189                                         from_path.to_string(), to_path.to_string()));
190         }
191         
192         out << in.rdbuf();
193         
194         if (!in || !out) {
195                 remove (to_path);
196                 throw filesystem_error(string_compose(_("Could not copy existing file %1 to %2"),
197                                         from_path.to_string(), to_path.to_string()));
198         }
199 }
200
201 string
202 basename (const path & p)
203 {
204         string base(p.leaf());
205
206         string::size_type n = base.rfind ('.');
207
208         return base.substr (0, n);
209 }
210
211 string
212 extension (const path & p)
213 {
214         string base(p.leaf());
215
216         string::size_type n = base.rfind ('.');
217
218         if (n != string::npos)
219         {
220                 return base.substr(n);
221         }
222
223         return string();
224
225 }
226
227 /** Take a (possibly) relative path and make it absolute */
228 path
229 get_absolute_path (const path & p)
230 {
231         Glib::RefPtr<Gio::File> f = Gio::File::create_for_path (p.to_string ());
232         return f->get_path ();
233 }
234
235 } // namespace sys
236
237 } // namespace PBD