r223: Implemented Chris Sawer's patch which adds a field for the leafname to the
[rox-filer.git] / ROX-Filer / src / support.c
blob803e02916670fa29238742a212a6ec6eb9184aff
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* support.c - (non-GUI) useful routines */
24 #include "config.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <ctype.h>
30 #include <sys/param.h>
31 #include <unistd.h>
32 #include <pwd.h>
33 #include <grp.h>
34 #include <fcntl.h>
35 #include <sys/wait.h>
36 #include <sys/stat.h>
37 #include <string.h>
38 #include <time.h>
40 #include <glib.h>
42 #include "main.h"
43 #include "support.h"
45 static GHashTable *uid_hash = NULL; /* UID -> User name */
46 static GHashTable *gid_hash = NULL; /* GID -> Group name */
48 /* Static prototypes */
51 /* Like g_strdup, but does realpath() too (if possible) */
52 char *pathdup(char *path)
54 char real[MAXPATHLEN];
56 g_return_val_if_fail(path != NULL, NULL);
58 if (realpath(path, real))
59 return g_strdup(real);
61 return g_strdup(path);
64 /* Join the path to the leaf (adding a / between them) and
65 * return a pointer to a buffer with the result. Buffer is valid until
66 * the next call to make_path.
68 GString *make_path(char *dir, char *leaf)
70 static GString *buffer = NULL;
72 if (!buffer)
73 buffer = g_string_new(NULL);
75 g_return_val_if_fail(dir != NULL, buffer);
76 g_return_val_if_fail(leaf != NULL, buffer);
78 g_string_sprintf(buffer, "%s%s%s",
79 dir,
80 dir[0] == '/' && dir[1] == '\0' ? "" : "/",
81 leaf);
83 return buffer;
86 /* Return our complete host name */
87 char *our_host_name()
89 static char *name = NULL;
91 if (!name)
93 char buffer[4096];
95 g_return_val_if_fail(gethostname(buffer, 4096) == 0,
96 "localhost");
98 buffer[4095] = '\0';
99 name = g_strdup(buffer);
102 return name;
105 /* fork() and run a new program.
106 * Returns the new PID, or 0 on failure.
108 pid_t spawn(char **argv)
110 return spawn_full(argv, NULL);
113 /* As spawn(), but cd to dir first (if dir is non-NULL) */
114 pid_t spawn_full(char **argv, char *dir)
116 int child;
118 child = fork();
120 if (child == -1)
121 return 0; /* Failure */
122 else if (child == 0)
124 /* We are the child process */
125 if (dir)
126 if (chdir(dir))
127 fprintf(stderr, "chdir() failed: %s\n",
128 g_strerror(errno));
129 dup2(to_error_log, STDERR_FILENO);
130 close_on_exec(STDERR_FILENO, FALSE);
131 execvp(argv[0], argv);
132 fprintf(stderr, "execvp(%s, ...) failed: %s\n",
133 argv[0],
134 g_strerror(errno));
135 _exit(0);
138 /* We are the parent */
139 return child;
142 void debug_free_string(void *data)
144 g_print("Freeing string '%s'\n", (char *) data);
145 g_free(data);
148 char *user_name(uid_t uid)
150 char *retval;
152 if (!uid_hash)
153 uid_hash = g_hash_table_new(NULL, NULL);
155 retval = g_hash_table_lookup(uid_hash, (gpointer) uid);
157 if (!retval)
159 struct passwd *passwd;
161 passwd = getpwuid(uid);
162 retval = passwd ? g_strdup(passwd->pw_name)
163 : g_strdup_printf("[%d]", (int) uid);
164 g_hash_table_insert(uid_hash, (gpointer) uid, retval);
167 return retval;
170 char *group_name(gid_t gid)
172 char *retval;
174 if (!gid_hash)
175 gid_hash = g_hash_table_new(NULL, NULL);
177 retval = g_hash_table_lookup(gid_hash, (gpointer) gid);
179 if (!retval)
181 struct group *group;
183 group = getgrgid(gid);
184 retval = group ? g_strdup(group->gr_name)
185 : g_strdup_printf("[%d]", (int) gid);
186 g_hash_table_insert(gid_hash, (gpointer) gid, retval);
189 return retval;
192 /* Return a string in the form '23Mb' in a static buffer valid until
193 * the next call.
195 char *format_size(unsigned long size)
197 static char *buffer = NULL;
198 char *units;
200 if (size >= PRETTY_SIZE_LIMIT)
202 size += 1023;
203 size >>= 10;
204 if (size >= PRETTY_SIZE_LIMIT)
206 size += 1023;
207 size >>= 10;
208 if (size >= PRETTY_SIZE_LIMIT)
210 size += 1023;
211 size >>= 10;
212 units = "Gb";
214 else
215 units = "Mb";
217 else
218 units = "K";
220 else
221 units = "bytes";
223 if (buffer)
224 g_free(buffer);
225 buffer = g_strdup_printf("%ld %s", size, units);
227 return buffer;
230 /* Return a string in the form '23Mb' in a static buffer valid until
231 * the next call. Aligned to the right.
233 char *format_size_aligned(unsigned long size)
235 static char *buffer = NULL;
236 char units;
238 if (size >= PRETTY_SIZE_LIMIT)
240 size += 1023;
241 size >>= 10;
242 if (size >= PRETTY_SIZE_LIMIT)
244 size += 1023;
245 size >>= 10;
246 if (size >= PRETTY_SIZE_LIMIT)
248 size += 1023;
249 size >>= 10;
250 units = 'G';
252 else
253 units = 'M';
255 else
256 units = 'K';
258 else
259 units = ' ';
261 if (buffer)
262 g_free(buffer);
263 buffer = g_strdup_printf("%4ld%c", size, units);
265 return buffer;
268 /* Fork and exec argv. Wait and return the child's exit status.
269 * -1 if spawn fails.
271 int fork_exec_wait(char **argv)
273 pid_t child;
274 int status = -1;
276 child = spawn_full(argv, NULL);
278 while (child)
280 if (waitpid(child, &status, 0) == -1)
282 if (errno != EINTR)
283 return -1;
285 else
286 break;
289 return status;
292 /* If a file has this UID and GID, which permissions apply to us?
293 * 0 = User, 1 = Group, 2 = World
295 gint applicable(uid_t uid, gid_t gid)
297 int i;
299 if (uid == euid)
300 return 0;
302 if (gid == egid)
303 return 1;
305 for (i = 0; i < ngroups; i++)
307 if (supplemental_groups[i] == gid)
308 return 1;
311 return 2;
314 /* Converts a file's mode to a string. Result is a pointer
315 * to a static buffer, valid until the next call.
317 char *pretty_permissions(mode_t m)
319 static char buffer[] = "rwx,rwx,rwx/UGT";
321 buffer[0] = m & S_IRUSR ? 'r' : '-';
322 buffer[1] = m & S_IWUSR ? 'w' : '-';
323 buffer[2] = m & S_IXUSR ? 'x' : '-';
325 buffer[4] = m & S_IRGRP ? 'r' : '-';
326 buffer[5] = m & S_IWGRP ? 'w' : '-';
327 buffer[6] = m & S_IXGRP ? 'x' : '-';
329 buffer[8] = m & S_IROTH ? 'r' : '-';
330 buffer[9] = m & S_IWOTH ? 'w' : '-';
331 buffer[10] = m & S_IXOTH ? 'x' : '-';
333 buffer[12] = m & S_ISUID ? 'U' : '-';
334 buffer[13] = m & S_ISGID ? 'G' : '-';
335 #ifdef S_ISVTX
336 buffer[14] = m & S_ISVTX ? 'T' : '-';
337 buffer[15] = 0;
338 #else
339 buffer[14] = 0;
340 #endif
342 return buffer;
345 /* Convert a URI to a local pathname (or NULL if it isn't local).
346 * The returned pointer points inside the input string.
347 * Possible formats:
348 * /path
349 * ///path
350 * //host/path
351 * file://host/path
353 char *get_local_path(char *uri)
355 char *host;
357 host = our_host_name();
359 if (*uri == '/')
361 char *path;
363 if (uri[1] != '/')
364 return uri; /* Just a local path - no host part */
366 path = strchr(uri + 2, '/');
367 if (!path)
368 return NULL; /* //something */
370 if (path - uri == 2)
371 return path; /* ///path */
372 if (strlen(host) == path - uri - 2 &&
373 strncmp(uri + 2, host, path - uri - 2) == 0)
374 return path; /* //myhost/path */
376 return NULL; /* From a different host */
378 else
380 if (strncasecmp(uri, "file:", 5))
381 return NULL; /* Don't know this format */
383 uri += 5;
385 if (*uri == '/')
386 return get_local_path(uri);
388 return NULL;
392 /* Set the close-on-exec flag for this FD.
393 * TRUE means that an exec()'d process will not get the FD.
395 void close_on_exec(int fd, gboolean close)
397 if (fcntl(fd, F_SETFD, close))
398 g_warning("fcntl() failed: %s\n", g_strerror(errno));
401 void set_blocking(int fd, gboolean blocking)
403 if (fcntl(fd, F_SETFL, blocking ? 0 : O_NONBLOCK))
404 g_warning("fcntl() failed: %s\n", g_strerror(errno));
407 /* Format this time nicely. The result is a pointer to a static buffer,
408 * valid until the next call.
410 char *pretty_time(time_t *time)
412 static char time_buf[32];
414 if (strftime(time_buf, sizeof(time_buf),
415 TIME_FORMAT, localtime(time)) == 0)
416 time_buf[0]= 0;
418 return time_buf;