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