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, char *estr)
    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