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