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