4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@users.sourceforge.net>.
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)
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
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 */
30 #include <sys/param.h>
44 static GHashTable
*uid_hash
= NULL
; /* UID -> User name */
45 static GHashTable
*gid_hash
= NULL
; /* GID -> Group name */
47 /* Static prototypes */
50 /* Like g_strdup, but does realpath() too (if possible) */
51 char *pathdup(char *path
)
53 char real
[MAXPATHLEN
];
55 g_return_val_if_fail(path
!= NULL
, NULL
);
57 if (realpath(path
, real
))
58 return g_strdup(real
);
60 return g_strdup(path
);
63 /* Join the path to the leaf (adding a / between them) and
64 * return a pointer to a buffer with the result. Buffer is valid until
65 * the next call to make_path.
67 GString
*make_path(char *dir
, char *leaf
)
69 static GString
*buffer
= NULL
;
72 buffer
= g_string_new(NULL
);
74 g_return_val_if_fail(dir
!= NULL
, buffer
);
75 g_return_val_if_fail(leaf
!= NULL
, buffer
);
77 g_string_sprintf(buffer
, "%s%s%s",
79 dir
[0] == '/' && dir
[1] == '\0' ? "" : "/",
85 /* Return our complete host name */
88 static char *name
= NULL
;
94 g_return_val_if_fail(gethostname(buffer
, 4096) == 0,
98 name
= g_strdup(buffer
);
104 /* fork() and run a new program.
105 * Returns the new PID, or 0 on failure.
107 pid_t
spawn(char **argv
)
109 return spawn_full(argv
, NULL
);
112 /* As spawn(), but cd to dir first (if dir is non-NULL) */
113 pid_t
spawn_full(char **argv
, char *dir
)
120 return 0; /* Failure */
123 /* We are the child process */
126 fprintf(stderr
, "chdir() failed: %s\n",
128 dup2(to_error_log
, STDERR_FILENO
);
129 close_on_exec(STDERR_FILENO
, FALSE
);
130 execvp(argv
[0], argv
);
131 fprintf(stderr
, "execvp(%s, ...) failed: %s\n",
137 /* We are the parent */
141 void debug_free_string(void *data
)
143 g_print("Freeing string '%s'\n", (char *) data
);
147 char *user_name(uid_t uid
)
152 uid_hash
= g_hash_table_new(NULL
, NULL
);
154 retval
= g_hash_table_lookup(uid_hash
, (gpointer
) uid
);
158 struct passwd
*passwd
;
160 passwd
= getpwuid(uid
);
161 retval
= passwd
? g_strdup(passwd
->pw_name
)
162 : g_strdup_printf("[%d]", (int) uid
);
163 g_hash_table_insert(uid_hash
, (gpointer
) uid
, retval
);
169 char *group_name(gid_t gid
)
174 gid_hash
= g_hash_table_new(NULL
, NULL
);
176 retval
= g_hash_table_lookup(gid_hash
, (gpointer
) gid
);
182 group
= getgrgid(gid
);
183 retval
= group
? g_strdup(group
->gr_name
)
184 : g_strdup_printf("[%d]", (int) gid
);
185 g_hash_table_insert(gid_hash
, (gpointer
) gid
, retval
);
191 /* Return a string in the form '23Mb' in a static buffer valid until
194 char *format_size(unsigned long size
)
196 static char *buffer
= NULL
;
199 if (size
>= PRETTY_SIZE_LIMIT
)
203 if (size
>= PRETTY_SIZE_LIMIT
)
207 if (size
>= PRETTY_SIZE_LIMIT
)
226 buffer
= g_strdup_printf("%ld %s", size
, units
);
231 /* Return a string in the form '23Mb' in a static buffer valid until
232 * the next call. Aligned to the right.
234 char *format_size_aligned(unsigned long size
)
236 static char *buffer
= NULL
;
239 if (size
>= PRETTY_SIZE_LIMIT
)
243 if (size
>= PRETTY_SIZE_LIMIT
)
247 if (size
>= PRETTY_SIZE_LIMIT
)
264 buffer
= g_strdup_printf("%4ld%c", size
, units
);
269 /* Fork and exec argv. Wait and return the child's exit status.
272 int fork_exec_wait(char **argv
)
277 child
= spawn_full(argv
, NULL
);
281 if (waitpid(child
, &status
, 0) == -1)
293 /* If a file has this UID and GID, which permissions apply to us?
294 * 0 = User, 1 = Group, 2 = World
296 gint
applicable(uid_t uid
, gid_t gid
)
306 for (i
= 0; i
< ngroups
; i
++)
308 if (supplemental_groups
[i
] == gid
)
315 /* Converts a file's mode to a string. Result is a pointer
316 * to a static buffer, valid until the next call.
318 char *pretty_permissions(mode_t m
)
320 static char buffer
[] = "rwx,rwx,rwx/UGT";
322 buffer
[0] = m
& S_IRUSR
? 'r' : '-';
323 buffer
[1] = m
& S_IWUSR
? 'w' : '-';
324 buffer
[2] = m
& S_IXUSR
? 'x' : '-';
326 buffer
[4] = m
& S_IRGRP
? 'r' : '-';
327 buffer
[5] = m
& S_IWGRP
? 'w' : '-';
328 buffer
[6] = m
& S_IXGRP
? 'x' : '-';
330 buffer
[8] = m
& S_IROTH
? 'r' : '-';
331 buffer
[9] = m
& S_IWOTH
? 'w' : '-';
332 buffer
[10] = m
& S_IXOTH
? 'x' : '-';
334 buffer
[12] = m
& S_ISUID
? 'U' : '-';
335 buffer
[13] = m
& S_ISGID
? 'G' : '-';
337 buffer
[14] = m
& S_ISVTX
? 'T' : '-';
346 /* Convert a URI to a local pathname (or NULL if it isn't local).
347 * The returned pointer points inside the input string.
354 char *get_local_path(char *uri
)
358 host
= our_host_name();
365 return uri
; /* Just a local path - no host part */
367 path
= strchr(uri
+ 2, '/');
369 return NULL
; /* //something */
372 return path
; /* ///path */
373 if (strlen(host
) == path
- uri
- 2 &&
374 strncmp(uri
+ 2, host
, path
- uri
- 2) == 0)
375 return path
; /* //myhost/path */
377 return NULL
; /* From a different host */
381 if (strncasecmp(uri
, "file:", 5))
382 return NULL
; /* Don't know this format */
387 return get_local_path(uri
);
393 /* Set the close-on-exec flag for this FD.
394 * TRUE means that an exec()'d process will not get the FD.
396 void close_on_exec(int fd
, gboolean close
)
398 if (fcntl(fd
, F_SETFD
, close
))
399 g_warning("fcntl() failed: %s\n", g_strerror(errno
));
402 void set_blocking(int fd
, gboolean blocking
)
404 if (fcntl(fd
, F_SETFL
, blocking
? 0 : O_NONBLOCK
))
405 g_warning("fcntl() failed: %s\n", g_strerror(errno
));
408 /* Format this time nicely. The result is a pointer to a static buffer,
409 * valid until the next call.
411 char *pretty_time(time_t *time
)
413 static char time_buf
[32];
415 if (strftime(time_buf
, sizeof(time_buf
),
416 TIME_FORMAT
, localtime(time
)) == 0)
423 # define O_NOFOLLOW 0x0
427 /* Copy data from 'read_fd' FD to 'write_fd' FD until EOF or error.
428 * Returns 0 on success, -1 on error (and sets errno).
430 static int copy_fd(int read_fd
, int write_fd
)
435 while ((got
= mc_read(read_fd
, buffer
, sizeof(buffer
))) > 0)
443 c
= mc_write(write_fd
, buffer
+ sent
, got
- sent
);
454 /* 'from' and 'to' are complete pathnames of files (not dirs or symlinks).
455 * This spawns 'cp' to do the copy if lstat() succeeds, otherwise we
456 * do the copy manually using vfs.
458 * Returns an error string, or NULL on success.
460 guchar
*copy_file(guchar
*from
, guchar
*to
)
462 char *argv
[] = {"cp", "-pRf", NULL
, NULL
, NULL
};
467 if (lstat(from
, &info
))
473 if (mc_lstat(from
, &info
))
474 return g_strerror(errno
);
476 /* Regular lstat() can't find it, but mc_lstat() can,
477 * so try reading it with VFS.
480 if (!S_ISREG(info
.st_mode
))
483 read_fd
= mc_open(from
, O_RDONLY
);
486 write_fd
= mc_open(to
,
487 O_NOFOLLOW
| O_WRONLY
| O_CREAT
| O_TRUNC
,
488 info
.st_mode
& 0777);
492 if (copy_fd(read_fd
, write_fd
))
495 /* (yes, the single | is right) */
496 if (mc_close(read_fd
) | mc_close(write_fd
))
497 return g_strerror(errno
);
505 return error
? g_strerror(error
) : _("Copy error");
512 if (fork_exec_wait(argv
))
513 return _("Copy failed");
517 /* 'word' has all special characters escaped so that it may be inserted
518 * into a shell command.
519 * Eg: 'My Dir?' becomes 'My\ Dir\?'. g_free() the result.
521 guchar
*shell_escape(guchar
*word
)
526 tmp
= g_string_new(NULL
);
530 if (strchr(" ?*['\"$~\\|();!`&", *word
))
531 g_string_append_c(tmp
, '\\');
532 g_string_append_c(tmp
, *word
);
537 g_string_free(tmp
, FALSE
);