1 /* This file contains file and directory reading file system call handlers. 2 * 3 * The entry points into this file are: 4 * do_read perform the READ file system call 5 * do_getdents perform the GETDENTS file system call 6 * 7 * Created: 8 * April 2009 (D.C. van Moolenbroek) 9 */ 10 11 #include "inc.h" 12 13 #include <dirent.h> 14 15 /*===========================================================================* 16 * do_read * 17 *===========================================================================*/ 18 ssize_t do_read(ino_t ino_nr, struct fsdriver_data *data, size_t count, 19 off_t pos, int call) 20 { 21 /* Read data from a file. 22 */ 23 struct inode *ino; 24 size_t size, off; 25 char *ptr; 26 int r, chunk; 27 28 if ((ino = find_inode(ino_nr)) == NULL) 29 return EINVAL; 30 31 if (IS_DIR(ino)) return EISDIR; 32 33 if ((r = get_handle(ino)) != OK) 34 return r; 35 36 assert(count > 0); 37 38 /* Use the buffer from below to eliminate extra copying. */ 39 size = sffs_table->t_readbuf(&ptr); 40 off = 0; 41 42 while (count > 0) { 43 chunk = MIN(count, size); 44 45 if ((r = sffs_table->t_read(ino->i_file, ptr, chunk, pos)) <= 0) 46 break; 47 48 chunk = r; 49 50 if ((r = fsdriver_copyout(data, off, ptr, chunk)) != OK) 51 break; 52 53 count -= chunk; 54 off += chunk; 55 pos += chunk; 56 } 57 58 if (r < 0) 59 return r; 60 61 return off; 62 } 63 64 /*===========================================================================* 65 * do_getdents * 66 *===========================================================================*/ 67 ssize_t do_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes, 68 off_t *posp) 69 { 70 /* Retrieve directory entries. 71 */ 72 struct fsdriver_dentry fsdentry; 73 char name[NAME_MAX+1]; 74 struct inode *ino, *child; 75 struct sffs_attr attr; 76 off_t pos; 77 int r; 78 /* must be at least sizeof(struct dirent) + NAME_MAX */ 79 static char buf[BLOCK_SIZE]; 80 81 if ((ino = find_inode(ino_nr)) == NULL) 82 return EINVAL; 83 84 if (!IS_DIR(ino)) return ENOTDIR; 85 86 if (*posp < 0 || *posp >= ULONG_MAX) return EINVAL; 87 88 /* We are going to need at least one free inode to store children in. */ 89 if (!have_free_inode()) return ENFILE; 90 91 /* If we don't have a directory handle yet, get one now. */ 92 if ((r = get_handle(ino)) != OK) 93 return r; 94 95 fsdriver_dentry_init(&fsdentry, data, bytes, buf, sizeof(buf)); 96 97 /* We use the seek position as file index number. The first position is for 98 * the "." entry, the second position is for the ".." entry, and the next 99 * position numbers each represent a file in the directory. 100 */ 101 for (;;) { 102 /* Determine which inode and name to use for this entry. 103 * We have no idea whether the host will give us "." and/or "..", 104 * so generate our own and skip those from the host. 105 */ 106 pos = (*posp)++; 107 108 if (pos == 0) { 109 /* Entry for ".". */ 110 child = ino; 111 112 strcpy(name, "."); 113 114 get_inode(child); 115 } 116 else if (pos == 1) { 117 /* Entry for "..", but only when there is a parent. */ 118 if (ino->i_parent == NULL) 119 continue; 120 121 child = ino->i_parent; 122 123 strcpy(name, ".."); 124 125 get_inode(child); 126 } 127 else { 128 /* Any other entry, not being "." or "..". */ 129 attr.a_mask = SFFS_ATTR_MODE; 130 131 r = sffs_table->t_readdir(ino->i_dir, pos - 2, name, 132 sizeof(name), &attr); 133 134 if (r != OK) { 135 /* No more entries? Then close the handle and stop. */ 136 if (r == ENOENT) { 137 put_handle(ino); 138 139 break; 140 } 141 142 /* FIXME: what if the error is ENAMETOOLONG? */ 143 return r; 144 } 145 146 if (!strcmp(name, ".") || !strcmp(name, "..")) 147 continue; 148 149 if ((child = lookup_dentry(ino, name)) == NULL) { 150 child = get_free_inode(); 151 152 /* We were promised a free inode! */ 153 assert(child != NULL); 154 155 child->i_flags = MODE_TO_DIRFLAG(attr.a_mode); 156 157 add_dentry(ino, name, child); 158 } 159 } 160 161 r = fsdriver_dentry_add(&fsdentry, INODE_NR(child), name, strlen(name), 162 IS_DIR(child) ? DT_DIR : DT_REG); 163 164 put_inode(child); 165 166 if (r < 0) 167 return r; 168 if (r == 0) 169 break; 170 } 171 172 return fsdriver_dentry_finish(&fsdentry); 173 } 174