_p9dir.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
_p9dir.c (4733B) | |
--- | |
1 #include <u.h> | |
2 #define NOPLAN9DEFINES | |
3 #include <libc.h> | |
4 #include <sys/types.h> | |
5 #include <sys/stat.h> | |
6 #include <dirent.h> | |
7 #include <pwd.h> | |
8 #include <grp.h> | |
9 | |
10 #if defined(__APPLE__) | |
11 #define _HAVESTGEN | |
12 #include <sys/disk.h> | |
13 static vlong | |
14 disksize(int fd, struct stat *st) | |
15 { | |
16 u64int bc; | |
17 u32int bs; | |
18 | |
19 bs = 0; | |
20 bc = 0; | |
21 ioctl(fd, DKIOCGETBLOCKSIZE, &bs); | |
22 ioctl(fd, DKIOCGETBLOCKCOUNT, &bc); | |
23 if(bs >0 && bc > 0) | |
24 return bc*bs; | |
25 return 0; | |
26 } | |
27 | |
28 #elif defined(__FreeBSD__) | |
29 #define _HAVESTGEN | |
30 #include <sys/disk.h> | |
31 #include <sys/disklabel.h> | |
32 #include <sys/ioctl.h> | |
33 static vlong | |
34 disksize(int fd, struct stat *st) | |
35 { | |
36 off_t mediasize; | |
37 | |
38 if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0) | |
39 return mediasize; | |
40 return 0; | |
41 } | |
42 | |
43 #elif defined(__OpenBSD__) | |
44 #define _HAVESTGEN | |
45 #include <sys/disklabel.h> | |
46 #include <sys/ioctl.h> | |
47 #include <sys/dkio.h> | |
48 static vlong | |
49 disksize(int fd, struct stat *st) | |
50 { | |
51 struct disklabel lab; | |
52 int n; | |
53 | |
54 if(!S_ISCHR(st->st_mode)) | |
55 return 0; | |
56 if(ioctl(fd, DIOCGDINFO, &lab) < 0) | |
57 return 0; | |
58 n = minor(st->st_rdev)&7; | |
59 if(n >= lab.d_npartitions) | |
60 return 0; | |
61 return (vlong)lab.d_partitions[n].p_size * lab.d_secsize; | |
62 } | |
63 | |
64 #elif defined(__linux__) | |
65 #include <linux/hdreg.h> | |
66 #include <linux/fs.h> | |
67 #include <sys/ioctl.h> | |
68 #undef major | |
69 #define major(dev) ((int)(((dev) >> 8) & 0xff)) | |
70 static vlong | |
71 disksize(int fd, struct stat *st) | |
72 { | |
73 u64int u64; | |
74 long l; | |
75 struct hd_geometry geo; | |
76 | |
77 memset(&geo, 0, sizeof geo); | |
78 l = 0; | |
79 u64 = 0; | |
80 #ifdef BLKGETSIZE64 | |
81 if(ioctl(fd, BLKGETSIZE64, &u64) >= 0) | |
82 return u64; | |
83 #endif | |
84 if(ioctl(fd, BLKGETSIZE, &l) >= 0) | |
85 return l*512; | |
86 if(ioctl(fd, HDIO_GETGEO, &geo) >= 0) | |
87 return (vlong)geo.heads*geo.sectors*geo.cylinders*512; | |
88 return 0; | |
89 } | |
90 | |
91 #else | |
92 static vlong | |
93 disksize(int fd, struct stat *st) | |
94 { | |
95 return 0; | |
96 } | |
97 #endif | |
98 | |
99 int _p9usepwlibrary = 1; | |
100 /* | |
101 * Caching the last group and passwd looked up is | |
102 * a significant win (stupidly enough) on most systems. | |
103 * It's not safe for threaded programs, but neither is using | |
104 * getpwnam in the first place, so I'm not too worried. | |
105 */ | |
106 int | |
107 _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str… | |
108 { | |
109 char *s; | |
110 char tmp[20]; | |
111 static struct group *g; | |
112 static struct passwd *p; | |
113 static int gid, uid; | |
114 int sz, fd; | |
115 | |
116 fd = -1; | |
117 USED(fd); | |
118 sz = 0; | |
119 if(d) | |
120 memset(d, 0, sizeof *d); | |
121 | |
122 /* name */ | |
123 s = strrchr(name, '/'); | |
124 if(s) | |
125 s++; | |
126 if(!s || !*s) | |
127 s = name; | |
128 if(*s == '/') | |
129 s++; | |
130 if(*s == 0) | |
131 s = "/"; | |
132 if(d){ | |
133 if(*str + strlen(s)+1 > estr) | |
134 d->name = "oops"; | |
135 else{ | |
136 strcpy(*str, s); | |
137 d->name = *str; | |
138 *str += strlen(*str)+1; | |
139 } | |
140 } | |
141 sz += strlen(s)+1; | |
142 | |
143 /* user */ | |
144 if(p && st->st_uid == uid && p->pw_uid == uid) | |
145 ; | |
146 else if(_p9usepwlibrary){ | |
147 p = getpwuid(st->st_uid); | |
148 uid = st->st_uid; | |
149 } | |
150 if(p == nil || st->st_uid != uid || p->pw_uid != uid){ | |
151 snprint(tmp, sizeof tmp, "%d", (int)st->st_uid); | |
152 s = tmp; | |
153 }else | |
154 s = p->pw_name; | |
155 sz += strlen(s)+1; | |
156 if(d){ | |
157 if(*str+strlen(s)+1 > estr) | |
158 d->uid = "oops"; | |
159 else{ | |
160 strcpy(*str, s); | |
161 d->uid = *str; | |
162 *str += strlen(*str)+1; | |
163 } | |
164 } | |
165 | |
166 /* group */ | |
167 if(g && st->st_gid == gid && g->gr_gid == gid) | |
168 ; | |
169 else if(_p9usepwlibrary){ | |
170 g = getgrgid(st->st_gid); | |
171 gid = st->st_gid; | |
172 } | |
173 if(g == nil || st->st_gid != gid || g->gr_gid != gid){ | |
174 snprint(tmp, sizeof tmp, "%d", (int)st->st_gid); | |
175 s = tmp; | |
176 }else | |
177 s = g->gr_name; | |
178 sz += strlen(s)+1; | |
179 if(d){ | |
180 if(*str + strlen(s)+1 > estr) | |
181 d->gid = "oops"; | |
182 else{ | |
183 strcpy(*str, s); | |
184 d->gid = *str; | |
185 *str += strlen(*str)+1; | |
186 } | |
187 } | |
188 | |
189 if(d){ | |
190 d->type = 'M'; | |
191 | |
192 d->muid = ""; | |
193 d->qid.path = st->st_ino; | |
194 /* | |
195 * do not include st->st_dev in path, because | |
196 * automounters give the same file system different | |
197 * st_dev values for successive mounts, causing | |
198 * spurious write warnings in acme and sam. | |
199 d->qid.path |= (uvlong)st->st_dev<<32; | |
200 */ | |
201 #ifdef _HAVESTGEN | |
202 d->qid.vers = st->st_gen; | |
203 #endif | |
204 if(d->qid.vers == 0) | |
205 d->qid.vers = st->st_mtime + st->st_ctime; | |
206 d->mode = st->st_mode&0777; | |
207 d->atime = st->st_atime; | |
208 d->mtime = st->st_mtime; | |
209 d->length = st->st_size; | |
210 | |
211 if(S_ISLNK(lst->st_mode)){ /* yes, lst not st */ | |
212 d->mode |= DMSYMLINK; | |
213 d->length = lst->st_size; | |
214 } | |
215 else if(S_ISDIR(st->st_mode)){ | |
216 d->length = 0; | |
217 d->mode |= DMDIR; | |
218 d->qid.type = QTDIR; | |
219 } | |
220 else if(S_ISFIFO(st->st_mode)) | |
221 d->mode |= DMNAMEDPIPE; | |
222 else if(S_ISSOCK(st->st_mode)) | |
223 d->mode |= DMSOCKET; | |
224 else if(S_ISBLK(st->st_mode)){ | |
225 d->mode |= DMDEVICE; | |
226 d->qid.path = ('b'<<16)|st->st_rdev; | |
227 } | |
228 else if(S_ISCHR(st->st_mode)){ | |
229 d->mode |= DMDEVICE; | |
230 d->qid.path = ('c'<<16)|st->st_rdev; | |
231 } | |
232 /* fetch real size for disks */ | |
233 if(S_ISBLK(lst->st_mode) || S_ISCHR(lst->st_mode)){ | |
234 if((fd = open(name, O_RDONLY)) >= 0){ | |
235 d->length = disksize(fd, st); | |
236 close(fd); | |
237 } | |
238 } | |
239 } | |
240 | |
241 return sz; | |
242 } | |
243 |