.
[gnulib.git] / lib / filemode.c
1 /* filemode.c -- make a string describing file modes
2    Copyright (C) 1985, 1990, 1993 Free Software Foundation, Inc.
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, or (at your option)
7    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 \f
18 #ifdef HAVE_CONFIG_H
19 #if defined (emacs) || defined (CONFIG_BROKETS)
20 #include <config.h>
21 #else
22 #include "config.h"
23 #endif
24 #endif
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28
29 #ifndef S_IREAD
30 #define S_IREAD S_IRUSR
31 #define S_IWRITE S_IWUSR
32 #define S_IEXEC S_IXUSR
33 #endif
34
35 #if 0 /* This is unreliable, since GCC 2.5 always has S_ISREG in its
36          fixed headers but it does not always have mode_t.
37          It seems safer not to try to use mode_t ever.  */
38 #if !defined(S_ISREG) || defined(NO_MODE_T)
39 /* Doesn't have POSIX.1 stat stuff or doesn't have mode_t.  */
40 #define mode_t unsigned short
41 #endif
42 #endif
43
44 #ifdef STAT_MACROS_BROKEN
45 #undef S_ISBLK
46 #undef S_ISCHR
47 #undef S_ISDIR
48 #undef S_ISFIFO
49 #undef S_ISLNK
50 #undef S_ISMPB
51 #undef S_ISMPC
52 #undef S_ISNWK
53 #undef S_ISREG
54 #undef S_ISSOCK
55 #endif /* STAT_MACROS_BROKEN.  */
56
57 #if !defined(S_ISBLK) && defined(S_IFBLK)
58 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
59 #endif
60 #if !defined(S_ISCHR) && defined(S_IFCHR)
61 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
62 #endif
63 #if !defined(S_ISDIR) && defined(S_IFDIR)
64 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
65 #endif
66 #if !defined(S_ISREG) && defined(S_IFREG)
67 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
68 #endif
69 #if !defined(S_ISFIFO) && defined(S_IFIFO)
70 #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
71 #endif
72 #if !defined(S_ISLNK) && defined(S_IFLNK)
73 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
74 #endif
75 #if !defined(S_ISSOCK) && defined(S_IFSOCK)
76 #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
77 #endif
78 #if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
79 #define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
80 #define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
81 #endif
82 #if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
83 #define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
84 #endif
85
86 void mode_string ();
87 static char ftypelet ();
88 static void rwx ();
89 static void setst ();
90
91 /* filemodestring - fill in string STR with an ls-style ASCII
92    representation of the st_mode field of file stats block STATP.
93    10 characters are stored in STR; no terminating null is added.
94    The characters stored in STR are:
95
96    0    File type.  'd' for directory, 'c' for character
97         special, 'b' for block special, 'm' for multiplex,
98         'l' for symbolic link, 's' for socket, 'p' for fifo,
99         '-' for regular, '?' for any other file type
100
101    1    'r' if the owner may read, '-' otherwise.
102
103    2    'w' if the owner may write, '-' otherwise.
104
105    3    'x' if the owner may execute, 's' if the file is
106         set-user-id, '-' otherwise.
107         'S' if the file is set-user-id, but the execute
108         bit isn't set.
109
110    4    'r' if group members may read, '-' otherwise.
111
112    5    'w' if group members may write, '-' otherwise.
113
114    6    'x' if group members may execute, 's' if the file is
115         set-group-id, '-' otherwise.
116         'S' if it is set-group-id but not executable.
117
118    7    'r' if any user may read, '-' otherwise.
119
120    8    'w' if any user may write, '-' otherwise.
121
122    9    'x' if any user may execute, 't' if the file is "sticky"
123         (will be retained in swap space after execution), '-'
124         otherwise.
125         'T' if the file is sticky but not executable.  */
126
127 void
128 filemodestring (statp, str)
129      struct stat *statp;
130      char *str;
131 {
132   mode_string (statp->st_mode, str);
133 }
134
135 /* Like filemodestring, but only the relevant part of the `struct stat'
136    is given as an argument.  */
137
138 void
139 mode_string (mode, str)
140      unsigned short mode;
141      char *str;
142 {
143   str[0] = ftypelet ((long) mode);
144   rwx ((mode & 0700) << 0, &str[1]);
145   rwx ((mode & 0070) << 3, &str[4]);
146   rwx ((mode & 0007) << 6, &str[7]);
147   setst (mode, str);
148 }
149
150 /* Return a character indicating the type of file described by
151    file mode BITS:
152    'd' for directories
153    'b' for block special files
154    'c' for character special files
155    'm' for multiplexor files
156    'l' for symbolic links
157    's' for sockets
158    'p' for fifos
159    '-' for regular files
160    '?' for any other file type.  */
161
162 static char
163 ftypelet (bits)
164      long bits;
165 {
166 #ifdef S_ISBLK
167   if (S_ISBLK (bits))
168     return 'b';
169 #endif
170   if (S_ISCHR (bits))
171     return 'c';
172   if (S_ISDIR (bits))
173     return 'd';
174   if (S_ISREG (bits))
175     return '-';
176 #ifdef S_ISFIFO
177   if (S_ISFIFO (bits))
178     return 'p';
179 #endif
180 #ifdef S_ISLNK
181   if (S_ISLNK (bits))
182     return 'l';
183 #endif
184 #ifdef S_ISSOCK
185   if (S_ISSOCK (bits))
186     return 's';
187 #endif
188 #ifdef S_ISMPC
189   if (S_ISMPC (bits))
190     return 'm';
191 #endif
192 #ifdef S_ISNWK
193   if (S_ISNWK (bits))
194     return 'n';
195 #endif
196   return '?';
197 }
198
199 /* Look at read, write, and execute bits in BITS and set
200    flags in CHARS accordingly.  */
201
202 static void
203 rwx (bits, chars)
204      unsigned short bits;
205      char *chars;
206 {
207   chars[0] = (bits & S_IREAD) ? 'r' : '-';
208   chars[1] = (bits & S_IWRITE) ? 'w' : '-';
209   chars[2] = (bits & S_IEXEC) ? 'x' : '-';
210 }
211
212 /* Set the 's' and 't' flags in file attributes string CHARS,
213    according to the file mode BITS.  */
214
215 static void
216 setst (bits, chars)
217      unsigned short bits;
218      char *chars;
219 {
220 #ifdef S_ISUID
221   if (bits & S_ISUID)
222     {
223       if (chars[3] != 'x')
224         /* Set-uid, but not executable by owner.  */
225         chars[3] = 'S';
226       else
227         chars[3] = 's';
228     }
229 #endif
230 #ifdef S_ISGID
231   if (bits & S_ISGID)
232     {
233       if (chars[6] != 'x')
234         /* Set-gid, but not executable by group.  */
235         chars[6] = 'S';
236       else
237         chars[6] = 's';
238     }
239 #endif
240 #ifdef S_ISVTX
241   if (bits & S_ISVTX)
242     {
243       if (chars[9] != 'x')
244         /* Sticky, but not executable by others.  */
245         chars[9] = 'T';
246       else
247         chars[9] = 't';
248     }
249 #endif
250 }