xref: /minix3/minix/lib/libsffs/stat.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1 /* This file contains file metadata retrieval and manipulation routines.
2  *
3  * The entry points into this file are:
4  *   get_mode		return a file's mode
5  *   do_stat		perform the STAT file system call
6  *   do_chmod		perform the CHMOD file system call
7  *   do_utime		perform the UTIME file system call
8  *
9  * Created:
10  *   April 2009 (D.C. van Moolenbroek)
11  */
12 
13 #include "inc.h"
14 
15 /*===========================================================================*
16  *				get_mode				     *
17  *===========================================================================*/
18 mode_t get_mode(struct inode *ino, int mode)
19 {
20 /* Return the mode for an inode, given the inode and the retrieved mode.
21  */
22 
23   mode &= S_IRWXU;
24   mode = mode | (mode >> 3) | (mode >> 6);
25 
26   if (IS_DIR(ino))
27 	mode = S_IFDIR | (mode & sffs_params->p_dir_mask);
28   else
29 	mode = S_IFREG | (mode & sffs_params->p_file_mask);
30 
31   if (read_only)
32 	mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
33 
34   return mode;
35 }
36 
37 /*===========================================================================*
38  *				do_stat					     *
39  *===========================================================================*/
40 int do_stat(ino_t ino_nr, struct stat *st)
41 {
42 /* Retrieve inode status.
43  */
44   struct inode *ino;
45   struct sffs_attr attr;
46   char path[PATH_MAX];
47   int r;
48 
49   /* Don't increase the inode refcount: it's already open anyway */
50   if ((ino = find_inode(ino_nr)) == NULL)
51 	return EINVAL;
52 
53   attr.a_mask = SFFS_ATTR_MODE | SFFS_ATTR_SIZE | SFFS_ATTR_CRTIME |
54 		SFFS_ATTR_ATIME | SFFS_ATTR_MTIME | SFFS_ATTR_CTIME;
55 
56   if ((r = verify_inode(ino, path, &attr)) != OK)
57 	return r;
58 
59   st->st_mode = get_mode(ino, attr.a_mode);
60   st->st_uid = sffs_params->p_uid;
61   st->st_gid = sffs_params->p_gid;
62   st->st_rdev = NO_DEV;
63   st->st_size = attr.a_size;
64   st->st_atimespec = attr.a_atime;
65   st->st_mtimespec = attr.a_mtime;
66   st->st_ctimespec = attr.a_ctime;
67   st->st_birthtimespec = attr.a_crtime;
68 
69   st->st_blocks = st->st_size / S_BLKSIZE;
70   if (st->st_size % S_BLKSIZE != 0)
71 	st->st_blocks += 1;
72 
73   st->st_blksize = BLOCK_SIZE;
74 
75   /* We could make this more accurate by iterating over directory inodes'
76    * children, counting how many of those are directories as well.
77    * It's just not worth it.
78    */
79   st->st_nlink = 0;
80   if (ino->i_parent != NULL) st->st_nlink++;
81   if (IS_DIR(ino)) {
82 	st->st_nlink++;
83 	if (HAS_CHILDREN(ino)) st->st_nlink++;
84   }
85 
86   return OK;
87 }
88 
89 /*===========================================================================*
90  *				do_chmod				     *
91  *===========================================================================*/
92 int do_chmod(ino_t ino_nr, mode_t *mode)
93 {
94 /* Change file mode.
95  */
96   struct inode *ino;
97   char path[PATH_MAX];
98   struct sffs_attr attr;
99   int r;
100 
101   if (read_only)
102 	return EROFS;
103 
104   if ((ino = find_inode(ino_nr)) == NULL)
105 	return EINVAL;
106 
107   if ((r = verify_inode(ino, path, NULL)) != OK)
108 	return r;
109 
110   /* Set the new file mode. */
111   attr.a_mask = SFFS_ATTR_MODE;
112   attr.a_mode = *mode; /* no need to convert in this direction */
113 
114   if ((r = sffs_table->t_setattr(path, &attr)) != OK)
115 	return r;
116 
117   /* We have no idea what really happened. Query for the mode again. */
118   if ((r = verify_path(path, ino, &attr, NULL)) != OK)
119 	return r;
120 
121   *mode = get_mode(ino, attr.a_mode);
122 
123   return OK;
124 }
125 
126 /*===========================================================================*
127  *				do_utime				     *
128  *===========================================================================*/
129 int do_utime(ino_t ino_nr, struct timespec *atime, struct timespec *mtime)
130 {
131 /* Set file times.
132  */
133   struct inode *ino;
134   char path[PATH_MAX];
135   struct sffs_attr attr;
136   int r;
137 
138   if (read_only)
139 	return EROFS;
140 
141   if ((ino = find_inode(ino_nr)) == NULL)
142 	return EINVAL;
143 
144   if ((r = verify_inode(ino, path, NULL)) != OK)
145 	return r;
146 
147   attr.a_mask = 0;
148 
149   switch (atime->tv_nsec) {
150   case UTIME_OMIT: /* do not touch */
151 	break;
152   case UTIME_NOW:
153 	/* XXX VFS should have time() into ACTIME, for compat; we trust it! */
154 	atime->tv_nsec = 0;
155 	/*FALLTHROUGH*/
156   default:
157 	attr.a_atime = *atime;
158 	attr.a_mask |= SFFS_ATTR_ATIME;
159 	break;
160   }
161 
162   switch (mtime->tv_nsec) {
163   case UTIME_OMIT: /* do not touch */
164 	break;
165   case UTIME_NOW:
166 	/* XXX VFS should have time() into MODTIME, for compat; we trust it! */
167 	mtime->tv_nsec = 0;
168 	/*FALLTHROUGH*/
169   default:
170 	attr.a_mtime = *mtime;
171 	attr.a_mask |= SFFS_ATTR_MTIME;
172 	break;
173   }
174 
175   return sffs_table->t_setattr(path, &attr);
176 }
177