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