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