xref: /minix3/minix/lib/libsffs/stat.c (revision eda6f5931d42c77e1480347b1fc3eef2f8d33806)
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 (state.s_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 *stat)
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   stat->st_dev = state.s_dev;
60   stat->st_ino = ino_nr;
61   stat->st_mode = get_mode(ino, attr.a_mode);
62   stat->st_uid = sffs_params->p_uid;
63   stat->st_gid = sffs_params->p_gid;
64   stat->st_rdev = NO_DEV;
65   stat->st_size = attr.a_size;
66   stat->st_atimespec = attr.a_atime;
67   stat->st_mtimespec = attr.a_mtime;
68   stat->st_ctimespec = attr.a_ctime;
69   stat->st_birthtimespec = attr.a_crtime;
70 
71   stat->st_blocks = stat->st_size / S_BLKSIZE;
72   if (stat->st_size % S_BLKSIZE != 0)
73 	stat->st_blocks += 1;
74 
75   stat->st_blksize = BLOCK_SIZE;
76 
77   /* We could make this more accurate by iterating over directory inodes'
78    * children, counting how many of those are directories as well.
79    * It's just not worth it.
80    */
81   stat->st_nlink = 0;
82   if (ino->i_parent != NULL) stat->st_nlink++;
83   if (IS_DIR(ino)) {
84 	stat->st_nlink++;
85 	if (HAS_CHILDREN(ino)) stat->st_nlink++;
86   }
87 
88   return OK;
89 }
90 
91 /*===========================================================================*
92  *				do_chmod				     *
93  *===========================================================================*/
94 int do_chmod(ino_t ino_nr, mode_t *mode)
95 {
96 /* Change file mode.
97  */
98   struct inode *ino;
99   char path[PATH_MAX];
100   struct sffs_attr attr;
101   int r;
102 
103   if (state.s_read_only)
104 	return EROFS;
105 
106   if ((ino = find_inode(ino_nr)) == NULL)
107 	return EINVAL;
108 
109   if ((r = verify_inode(ino, path, NULL)) != OK)
110 	return r;
111 
112   /* Set the new file mode. */
113   attr.a_mask = SFFS_ATTR_MODE;
114   attr.a_mode = *mode; /* no need to convert in this direction */
115 
116   if ((r = sffs_table->t_setattr(path, &attr)) != OK)
117 	return r;
118 
119   /* We have no idea what really happened. Query for the mode again. */
120   if ((r = verify_path(path, ino, &attr, NULL)) != OK)
121 	return r;
122 
123   *mode = get_mode(ino, attr.a_mode);
124 
125   return OK;
126 }
127 
128 /*===========================================================================*
129  *				do_utime				     *
130  *===========================================================================*/
131 int do_utime(ino_t ino_nr, struct timespec *atime, struct timespec *mtime)
132 {
133 /* Set file times.
134  */
135   struct inode *ino;
136   char path[PATH_MAX];
137   struct sffs_attr attr;
138   int r;
139 
140   if (state.s_read_only)
141 	return EROFS;
142 
143   if ((ino = find_inode(ino_nr)) == NULL)
144 	return EINVAL;
145 
146   if ((r = verify_inode(ino, path, NULL)) != OK)
147 	return r;
148 
149   attr.a_mask = 0;
150 
151   switch (atime->tv_nsec) {
152   case UTIME_OMIT: /* do not touch */
153 	break;
154   case UTIME_NOW:
155 	/* XXX VFS should have time() into ACTIME, for compat; we trust it! */
156 	atime->tv_nsec = 0;
157 	/*FALLTHROUGH*/
158   default:
159 	attr.a_atime = *atime;
160 	attr.a_mask |= SFFS_ATTR_ATIME;
161 	break;
162   }
163 
164   switch (mtime->tv_nsec) {
165   case UTIME_OMIT: /* do not touch */
166 	break;
167   case UTIME_NOW:
168 	/* XXX VFS should have time() into MODTIME, for compat; we trust it! */
169 	mtime->tv_nsec = 0;
170 	/*FALLTHROUGH*/
171   default:
172 	attr.a_mtime = *mtime;
173 	attr.a_mask |= SFFS_ATTR_MTIME;
174 	break;
175   }
176 
177   return sffs_table->t_setattr(path, &attr);
178 }
179