1 1.37 mrg /* $NetBSD: ustarfs.c,v 1.37 2019/11/21 21:45:34 mrg Exp $ */ 2 1.1 ross 3 1.1 ross /* [Notice revision 2.2] 4 1.1 ross * Copyright (c) 1997, 1998 Avalon Computer Systems, Inc. 5 1.1 ross * All rights reserved. 6 1.1 ross * 7 1.1 ross * Author: Ross Harvey 8 1.1 ross * 9 1.1 ross * Redistribution and use in source and binary forms, with or without 10 1.1 ross * modification, are permitted provided that the following conditions 11 1.1 ross * are met: 12 1.1 ross * 1. Redistributions of source code must retain the above copyright and 13 1.1 ross * author notice, this list of conditions, and the following disclaimer. 14 1.1 ross * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 ross * notice, this list of conditions and the following disclaimer in the 16 1.1 ross * documentation and/or other materials provided with the distribution. 17 1.1 ross * 3. Neither the name of Avalon Computer Systems, Inc. nor the names of 18 1.1 ross * its contributors may be used to endorse or promote products derived 19 1.1 ross * from this software without specific prior written permission. 20 1.1 ross * 4. This copyright will be assigned to The NetBSD Foundation on 21 1.1 ross * 1/1/2000 unless these terms (including possibly the assignment 22 1.1 ross * date) are updated in writing by Avalon prior to the latest specified 23 1.1 ross * assignment date. 24 1.1 ross * 25 1.1 ross * THIS SOFTWARE IS PROVIDED BY AVALON COMPUTER SYSTEMS, INC. AND CONTRIBUTORS 26 1.1 ross * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 ross * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 ross * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AVALON OR THE CONTRIBUTORS 29 1.1 ross * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 ross * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 ross * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 ross * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 ross * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 ross * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 ross * POSSIBILITY OF SUCH DAMAGE. 36 1.1 ross */ 37 1.1 ross 38 1.1 ross 39 1.1 ross /* 40 1.1 ross ******************************* USTAR FS ******************************* 41 1.1 ross */ 42 1.1 ross 43 1.1 ross /* 44 1.1 ross * Implement an ROFS with an 8K boot area followed by ustar-format data. 45 1.1 ross * The point: minimal FS overhead, and it's easy (well, `possible') to 46 1.1 ross * split files over multiple volumes. 47 1.1 ross * 48 1.1 ross * XXX - TODO LIST 49 1.1 ross * --- - ---- ---- 50 1.1 ross * XXX - tag volume numbers and verify that the correct volume is 51 1.1 ross * inserted after volume swaps. 52 1.1 ross * 53 1.1 ross * XXX - stop hardwiring FS metadata for floppies...embed it in a file, 54 1.1 ross * file name, or something. (Remember __SYMDEF? :-) 55 1.1 ross * 56 1.8 cgd * XXX Does not currently implement: 57 1.8 cgd * XXX 58 1.8 cgd * XXX LIBSA_NO_FS_CLOSE 59 1.8 cgd * XXX LIBSA_NO_FS_SEEK 60 1.8 cgd * XXX LIBSA_NO_FS_WRITE 61 1.8 cgd * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?) 62 1.8 cgd * XXX LIBSA_FS_SINGLECOMPONENT 63 1.1 ross */ 64 1.1 ross 65 1.14 thorpej #ifdef _STANDALONE 66 1.14 thorpej #include <lib/libkern/libkern.h> 67 1.14 thorpej #else 68 1.14 thorpej #include <string.h> 69 1.14 thorpej #endif 70 1.1 ross #include "stand.h" 71 1.1 ross #include "ustarfs.h" 72 1.1 ross 73 1.2 ross #define BBSIZE 8192 74 1.1 ross #define USTAR_NAME_BLOCK 512 75 1.1 ross 76 1.2 ross /* 77 1.2 ross * Virtual offset: relative to start of ustar archive 78 1.2 ross * Logical offset: volume-relative 79 1.2 ross * Physical offset: the usual meaning 80 1.2 ross */ 81 1.2 ross 82 1.2 ross /* virtual offset to volume number */ 83 1.24 perry 84 1.24 perry #define vda2vn(_v,_volsize) ((_v) / (_volsize)) 85 1.2 ross 86 1.2 ross /* conversions between the three different levels of disk addresses */ 87 1.2 ross 88 1.2 ross #define vda2lda(_v,_volsize) ((_v) % (_volsize)) 89 1.2 ross #define lda2vda(_v,_volsize,_volnumber) ((_v) + (_volsize) * (_volnumber)) 90 1.2 ross 91 1.2 ross #define lda2pda(_lda) ((_lda) + ustarfs_mode_offset) 92 1.2 ross #define pda2lda(_pda) ((_pda) - ustarfs_mode_offset) 93 1.2 ross /* 94 1.2 ross * Change this to off_t if you want to support big volumes. If we only use 95 1.2 ross * ustarfs on floppies it can stay int for libsa code density. 96 1.2 ross * 97 1.2 ross * It needs to be signed. 98 1.2 ross */ 99 1.2 ross typedef int ustoffs; 100 1.2 ross 101 1.1 ross typedef struct ustar_struct { 102 1.1 ross char ust_name[100], 103 1.1 ross ust_mode[8], 104 1.1 ross ust_uid[8], 105 1.1 ross ust_gid[8], 106 1.1 ross ust_size[12], 107 1.1 ross ust_misc[12 + 8 + 1 + 100], 108 1.18 matt ust_magic[6], 109 1.1 ross /* there is more, but we don't care */ 110 1.18 matt ust_pad[1]; /* make it aligned */ 111 1.1 ross } ustar_t; 112 1.1 ross 113 1.1 ross /* 114 1.17 lukem * We buffer one even cylinder of data...it's actually only really one 115 1.1 ross * cyl on a 1.44M floppy, but on other devices it's fast enough with any 116 1.1 ross * kind of block buffering, so we optimize for the slowest device. 117 1.1 ross */ 118 1.1 ross 119 1.30 isaki #ifndef USTAR_SECT_PER_CYL 120 1.30 isaki #define USTAR_SECT_PER_CYL (18 * 2) 121 1.30 isaki #endif 122 1.30 isaki 123 1.1 ross typedef struct ust_active_struct { 124 1.1 ross ustar_t uas_active; 125 1.30 isaki char uas_1cyl[USTAR_SECT_PER_CYL * 512]; 126 1.2 ross ustoffs uas_volsize; /* XXX this is hardwired now */ 127 1.2 ross ustoffs uas_windowbase; /* relative to volume 0 */ 128 1.2 ross ustoffs uas_filestart; /* relative to volume 0 */ 129 1.2 ross ustoffs uas_fseek; /* relative to file */ 130 1.2 ross ustoffs uas_filesize; /* relative to volume 0 */ 131 1.1 ross int uas_init_window; /* data present in window */ 132 1.1 ross int uas_init_fs; /* ust FS actually found */ 133 1.2 ross int uas_volzerosig; /* ID volume 0 by signature */ 134 1.11 ross int uas_sigdone; /* did sig already */ 135 1.2 ross int uas_offset; /* amount of cylinder below lba 0 */ 136 1.1 ross } ust_active_t; 137 1.1 ross 138 1.3 ross static const char formatid[] = "USTARFS", 139 1.31 isaki metaname[] = "USTAR.volsize."; 140 1.1 ross 141 1.21 mycroft static const int ustarfs_mode_offset = BBSIZE; 142 1.1 ross 143 1.32 tsutsui static int checksig(ust_active_t *); 144 1.32 tsutsui static int convert(const char *, int, int); 145 1.32 tsutsui static int get_volume(struct open_file *, int); 146 1.3 ross static void setwindow(ust_active_t *, ustoffs, ustoffs); 147 1.32 tsutsui static int real_fs_cylinder_read(struct open_file *, ustoffs, int); 148 1.32 tsutsui static int ustarfs_cylinder_read(struct open_file *, ustoffs, int); 149 1.32 tsutsui static void ustarfs_sscanf(const char *, const char *, int *); 150 1.32 tsutsui static int read512block(struct open_file *, ustoffs, char block[512]); 151 1.32 tsutsui static int init_volzero_sig(struct open_file *); 152 1.1 ross 153 1.16 minoura #ifdef HAVE_CHANGEDISK_HOOK 154 1.16 minoura /* 155 1.16 minoura * Called when the next volume is prompted. 156 1.16 minoura * Machine dependent code can eject the medium etc. 157 1.16 minoura * The new medium must be ready when this hook returns. 158 1.16 minoura */ 159 1.32 tsutsui void changedisk_hook(struct open_file *); 160 1.16 minoura #endif 161 1.16 minoura 162 1.1 ross static int 163 1.31 isaki convert(const char *f, int base, int fw) 164 1.1 ross { 165 1.1 ross int i, c, result = 0; 166 1.1 ross 167 1.1 ross while(fw > 0 && *f == ' ') { 168 1.1 ross --fw; 169 1.1 ross ++f; 170 1.1 ross } 171 1.1 ross for(i = 0; i < fw; ++i) { 172 1.1 ross c = f[i]; 173 1.1 ross if ('0' <= c && c < '0' + base) { 174 1.1 ross c -= '0'; 175 1.1 ross result = result * base + c; 176 1.1 ross } else break; 177 1.1 ross } 178 1.1 ross return result; 179 1.1 ross } 180 1.1 ross 181 1.1 ross static void 182 1.31 isaki ustarfs_sscanf(const char *s, const char *f, int *xi) 183 1.1 ross { 184 1.31 isaki 185 1.1 ross *xi = convert(s, 8, convert(f + 1, 10, 99)); 186 1.1 ross } 187 1.1 ross 188 1.1 ross static int 189 1.31 isaki ustarfs_cylinder_read(struct open_file *f, ustoffs seek2, int forcelabel) 190 1.1 ross { 191 1.11 ross int i, e; 192 1.11 ross 193 1.11 ross for (i = 0; i < 3; ++i) { 194 1.11 ross e = real_fs_cylinder_read(f, seek2, forcelabel); 195 1.11 ross if (e == 0) 196 1.11 ross return 0; 197 1.11 ross } 198 1.11 ross return e; 199 1.11 ross } 200 1.11 ross 201 1.11 ross static int 202 1.31 isaki real_fs_cylinder_read(struct open_file *f, ustoffs seek2, int forcelabel) 203 1.11 ross { 204 1.10 ross int i; 205 1.4 bad int e = 0; /* XXX work around gcc warning */ 206 1.3 ross ustoffs lda; 207 1.3 ross char *xferbase; 208 1.1 ross ust_active_t *ustf; 209 1.31 isaki size_t xferrqst, xfercount; 210 1.1 ross 211 1.1 ross ustf = f->f_fsdata; 212 1.3 ross xferrqst = sizeof ustf->uas_1cyl; 213 1.3 ross xferbase = ustf->uas_1cyl; 214 1.3 ross lda = pda2lda(seek2); 215 1.3 ross if (lda < 0) { 216 1.3 ross lda = -lda; 217 1.3 ross ustf->uas_offset = lda; 218 1.3 ross /* 219 1.3 ross * don't read the label unless we have to. (Preserve 220 1.3 ross * sequential block access so tape boot works.) 221 1.3 ross */ 222 1.3 ross if (!forcelabel) { 223 1.3 ross memset(xferbase, 0, lda); 224 1.3 ross xferrqst -= lda; 225 1.3 ross xferbase += lda; 226 1.3 ross seek2 += lda; 227 1.3 ross } 228 1.31 isaki } else { 229 1.3 ross ustf->uas_offset = 0; 230 1.31 isaki } 231 1.3 ross while(xferrqst > 0) { 232 1.9 christos #if !defined(LIBSA_NO_TWIDDLE) 233 1.9 christos twiddle(); 234 1.9 christos #endif 235 1.10 ross for (i = 0; i < 3; ++i) { 236 1.10 ross e = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 237 1.10 ross seek2 / 512, xferrqst, xferbase, &xfercount); 238 1.10 ross if (e == 0) 239 1.10 ross break; 240 1.10 ross printf("@"); 241 1.10 ross } 242 1.3 ross if (e) 243 1.3 ross break; 244 1.3 ross if (xfercount != xferrqst) 245 1.3 ross printf("Warning, unexpected short transfer %d/%d\n", 246 1.3 ross (int)xfercount, (int)xferrqst); 247 1.3 ross xferrqst -= xfercount; 248 1.3 ross xferbase += xfercount; 249 1.10 ross seek2 += xfercount; 250 1.2 ross } 251 1.1 ross return e; 252 1.1 ross } 253 1.1 ross 254 1.1 ross static int 255 1.31 isaki checksig(ust_active_t *ustf) 256 1.2 ross { 257 1.2 ross int i, rcs; 258 1.2 ross 259 1.23 fvdl for(i = rcs = 0; i < (int)(sizeof ustf->uas_1cyl); ++i) 260 1.2 ross rcs += ustf->uas_1cyl[i]; 261 1.2 ross return rcs; 262 1.2 ross } 263 1.2 ross 264 1.2 ross static int 265 1.31 isaki get_volume(struct open_file *f, int vn) 266 1.2 ross { 267 1.2 ross int e, needvolume, havevolume; 268 1.2 ross ust_active_t *ustf; 269 1.2 ross 270 1.2 ross ustf = f->f_fsdata; 271 1.2 ross havevolume = vda2vn(ustf->uas_windowbase, ustf->uas_volsize); 272 1.2 ross needvolume = vn; 273 1.2 ross while(havevolume != needvolume) { 274 1.2 ross printf("\nPlease "); 275 1.2 ross if (havevolume >= 0) 276 1.2 ross printf("remove disk %d, ", havevolume + 1); 277 1.15 lukem printf("insert disk %d, and press return...", 278 1.2 ross needvolume + 1); 279 1.16 minoura #ifdef HAVE_CHANGEDISK_HOOK 280 1.16 minoura changedisk_hook(f); 281 1.16 minoura #else 282 1.20 jmmv for (;;) { 283 1.20 jmmv int c = getchar(); 284 1.20 jmmv if ((c == '\n') || (c == '\r')) 285 1.20 jmmv break; 286 1.20 jmmv } 287 1.16 minoura #endif 288 1.2 ross printf("\n"); 289 1.11 ross e = ustarfs_cylinder_read(f, 0, needvolume != 0); 290 1.2 ross if (e) 291 1.2 ross return e; 292 1.2 ross if(strncmp(formatid, ustf->uas_1cyl, strlen(formatid))) { 293 1.2 ross /* no magic, might be OK if we want volume 0 */ 294 1.2 ross if (ustf->uas_volzerosig == checksig(ustf)) { 295 1.2 ross havevolume = 0; 296 1.2 ross continue; 297 1.2 ross } 298 1.2 ross printf("Disk is not from the volume set?!\n"); 299 1.2 ross havevolume = -2; 300 1.2 ross continue; 301 1.2 ross } 302 1.2 ross ustarfs_sscanf(ustf->uas_1cyl + strlen(formatid), "%9o", 303 1.2 ross &havevolume); 304 1.2 ross --havevolume; 305 1.2 ross } 306 1.2 ross return 0; 307 1.2 ross } 308 1.2 ross 309 1.3 ross static void 310 1.3 ross setwindow(ust_active_t *ustf, ustoffs pda, ustoffs vda) 311 1.3 ross { 312 1.3 ross ustf->uas_windowbase = lda2vda(pda2lda(pda), ustf->uas_volsize, 313 1.31 isaki vda2vn(vda, ustf->uas_volsize)) 314 1.31 isaki + ustf->uas_offset; 315 1.3 ross ustf->uas_init_window = 1; 316 1.3 ross } 317 1.3 ross 318 1.2 ross static int 319 1.31 isaki read512block(struct open_file *f, ustoffs vda, char block[512]) 320 1.1 ross { 321 1.3 ross ustoffs pda; 322 1.1 ross ssize_t e; 323 1.2 ross int dienow; 324 1.1 ross ust_active_t *ustf; 325 1.1 ross 326 1.2 ross dienow = 0; 327 1.1 ross ustf = f->f_fsdata; 328 1.2 ross 329 1.2 ross /* 330 1.2 ross * if (vda in window) 331 1.2 ross * copy out and return data 332 1.2 ross * if (vda is on some other disk) 333 1.2 ross * do disk swap 334 1.2 ross * get physical disk address 335 1.2 ross * round down to cylinder boundary 336 1.17 lukem * read cylinder 337 1.2 ross * set window (in vda space) and try again 338 1.2 ross * [ there is an implicit assumption that windowbase always identifies 339 1.2 ross * the current volume, even if initwindow == 0. This way, a 340 1.2 ross * windowbase of 0 causes the initial volume to be disk 0 ] 341 1.2 ross */ 342 1.1 ross tryagain: 343 1.1 ross if(ustf->uas_init_window 344 1.2 ross && ustf->uas_windowbase <= vda && vda < 345 1.23 fvdl ustf->uas_windowbase + 346 1.23 fvdl (int)(sizeof ustf->uas_1cyl) - ustf->uas_offset) { 347 1.2 ross memcpy(block, ustf->uas_1cyl 348 1.2 ross + (vda - ustf->uas_windowbase) 349 1.2 ross + ustf->uas_offset, 512); 350 1.1 ross return 0; 351 1.1 ross } 352 1.1 ross if (dienow++) 353 1.1 ross panic("ustarfs read512block"); 354 1.2 ross ustf->uas_init_window = 0; 355 1.2 ross e = get_volume(f, vda2vn(vda, ustf->uas_volsize)); 356 1.2 ross if (e) 357 1.2 ross return e; 358 1.2 ross pda = lda2pda(vda2lda(vda, ustf->uas_volsize)); 359 1.2 ross pda-= pda % sizeof ustf->uas_1cyl; 360 1.3 ross e = ustarfs_cylinder_read(f, pda, 0); 361 1.1 ross if (e) 362 1.1 ross return e; 363 1.3 ross setwindow(ustf, pda, vda); 364 1.1 ross goto tryagain; 365 1.1 ross } 366 1.1 ross 367 1.11 ross static int 368 1.31 isaki init_volzero_sig(struct open_file *f) 369 1.11 ross { 370 1.11 ross int e; 371 1.11 ross ust_active_t *ustf; 372 1.11 ross 373 1.11 ross ustf = f->f_fsdata; 374 1.11 ross if (!ustf->uas_sigdone) { 375 1.11 ross e = ustarfs_cylinder_read(f, 0, 0); 376 1.11 ross if (e) 377 1.11 ross return e; 378 1.11 ross ustf->uas_volzerosig = checksig(ustf); 379 1.11 ross setwindow(ustf, 0, 0); 380 1.11 ross } 381 1.11 ross return 0; 382 1.11 ross } 383 1.11 ross 384 1.36 mrg /* 385 1.36 mrg * XXX Hack alert. GCC 8.3 mis-compiles this function and calls 386 1.36 mrg * strncmp() with the wrong second pointer, as seen in PR#54703. 387 1.36 mrg * 388 1.36 mrg * Until the real cause is located, work around it by using -O1 389 1.36 mrg * for this function. 390 1.36 mrg */ 391 1.37 mrg #if defined(__i386__) && !defined(__clang__) 392 1.36 mrg __attribute__((__optimize__("O1"))) 393 1.36 mrg #endif 394 1.33 joerg __compactcall int 395 1.31 isaki ustarfs_open(const char *path, struct open_file *f) 396 1.1 ross { 397 1.1 ross ust_active_t *ustf; 398 1.2 ross ustoffs offset; 399 1.1 ross char block[512]; 400 1.1 ross int filesize; 401 1.1 ross int e, e2; 402 1.3 ross int newvolblocks; 403 1.1 ross 404 1.1 ross if (*path == '/') 405 1.1 ross ++path; 406 1.1 ross f->f_fsdata = ustf = alloc(sizeof *ustf); 407 1.1 ross memset(ustf, 0, sizeof *ustf); 408 1.2 ross offset = 0; 409 1.3 ross /* default to 2880 sector floppy */ 410 1.3 ross ustf->uas_volsize = 80 * 2 * 18 * 512 - lda2pda(0); 411 1.1 ross ustf->uas_fseek = 0; 412 1.11 ross e = init_volzero_sig(f); 413 1.11 ross if (e) 414 1.11 ross return e; 415 1.12 ross e2 = EINVAL; 416 1.1 ross for(;;) { 417 1.1 ross ustf->uas_filestart = offset; 418 1.12 ross e = read512block(f, offset, block); 419 1.12 ross if (e) 420 1.12 ross break; 421 1.12 ross memcpy(&ustf->uas_active, block, sizeof ustf->uas_active); 422 1.12 ross if(strncmp(ustf->uas_active.ust_magic, "ustar", 5)) { 423 1.1 ross e = e2; 424 1.1 ross break; 425 1.1 ross } 426 1.12 ross e2 = ENOENT; /* it must be an actual ustarfs */ 427 1.1 ross ustf->uas_init_fs = 1; 428 1.3 ross /* if volume metadata is found, use it */ 429 1.3 ross if(strncmp(ustf->uas_active.ust_name, metaname, 430 1.3 ross strlen(metaname)) == 0) { 431 1.3 ross ustarfs_sscanf(ustf->uas_active.ust_name 432 1.3 ross + strlen(metaname), "%99o", &newvolblocks); 433 1.3 ross ustf->uas_volsize = newvolblocks * 512 434 1.3 ross - lda2pda(0); 435 1.3 ross } 436 1.1 ross ustarfs_sscanf(ustf->uas_active.ust_size,"%12o",&filesize); 437 1.1 ross if(strncmp(ustf->uas_active.ust_name, path, 438 1.1 ross sizeof ustf->uas_active.ust_name) == 0) { 439 1.1 ross ustf->uas_filesize = filesize; 440 1.1 ross break; 441 1.1 ross } 442 1.1 ross offset += USTAR_NAME_BLOCK + filesize; 443 1.1 ross filesize %= 512; 444 1.1 ross if (filesize) 445 1.1 ross offset += 512 - filesize; 446 1.1 ross } 447 1.1 ross if (e) { 448 1.26 christos dealloc(ustf, sizeof *ustf); 449 1.1 ross f->f_fsdata = 0; 450 1.1 ross } 451 1.1 ross return e; 452 1.1 ross } 453 1.1 ross 454 1.8 cgd #ifndef LIBSA_NO_FS_WRITE 455 1.33 joerg __compactcall int 456 1.31 isaki ustarfs_write(struct open_file *f, void *start, size_t size, size_t *resid) 457 1.1 ross { 458 1.31 isaki 459 1.31 isaki return EROFS; 460 1.1 ross } 461 1.8 cgd #endif /* !LIBSA_NO_FS_WRITE */ 462 1.1 ross 463 1.8 cgd #ifndef LIBSA_NO_FS_SEEK 464 1.33 joerg __compactcall off_t 465 1.31 isaki ustarfs_seek(struct open_file *f, off_t offs, int whence) 466 1.1 ross { 467 1.1 ross ust_active_t *ustf; 468 1.1 ross 469 1.1 ross ustf = f->f_fsdata; 470 1.1 ross switch (whence) { 471 1.31 isaki case SEEK_SET: 472 1.1 ross ustf->uas_fseek = offs; 473 1.1 ross break; 474 1.31 isaki case SEEK_CUR: 475 1.1 ross ustf->uas_fseek += offs; 476 1.1 ross break; 477 1.31 isaki case SEEK_END: 478 1.1 ross ustf->uas_fseek = ustf->uas_filesize - offs; 479 1.1 ross break; 480 1.31 isaki default: 481 1.1 ross return -1; 482 1.1 ross } 483 1.1 ross return ustf->uas_fseek; 484 1.1 ross } 485 1.19 lukem #endif /* !LIBSA_NO_FS_SEEK */ 486 1.1 ross 487 1.33 joerg __compactcall int 488 1.31 isaki ustarfs_read(struct open_file *f, void *start, size_t size, size_t *resid) 489 1.1 ross { 490 1.1 ross ust_active_t *ustf; 491 1.1 ross int e; 492 1.1 ross char *space512; 493 1.31 isaki int blkoffs; 494 1.31 isaki int readoffs; 495 1.31 isaki int bufferoffset; 496 1.1 ross size_t seg; 497 1.31 isaki size_t infile; 498 1.31 isaki size_t inbuffer; 499 1.1 ross 500 1.1 ross e = 0; 501 1.1 ross space512 = alloc(512); 502 1.1 ross ustf = f->f_fsdata; 503 1.1 ross while(size != 0) { 504 1.1 ross if (ustf->uas_fseek >= ustf->uas_filesize) 505 1.1 ross break; 506 1.1 ross bufferoffset = ustf->uas_fseek % 512; 507 1.1 ross blkoffs = ustf->uas_fseek - bufferoffset; 508 1.1 ross readoffs = ustf->uas_filestart + 512 + blkoffs; 509 1.1 ross e = read512block(f, readoffs, space512); 510 1.1 ross if (e) 511 1.1 ross break; 512 1.1 ross seg = size; 513 1.1 ross inbuffer = 512 - bufferoffset; 514 1.1 ross if (inbuffer < seg) 515 1.1 ross seg = inbuffer; 516 1.1 ross infile = ustf->uas_filesize - ustf->uas_fseek; 517 1.1 ross if (infile < seg) 518 1.1 ross seg = infile; 519 1.1 ross memcpy(start, space512 + bufferoffset, seg); 520 1.1 ross ustf->uas_fseek += seg; 521 1.29 he start = (char *)start + seg; 522 1.31 isaki size -= seg; 523 1.1 ross } 524 1.1 ross if (resid) 525 1.1 ross *resid = size; 526 1.26 christos dealloc(space512, 512); 527 1.1 ross return e; 528 1.1 ross } 529 1.1 ross 530 1.33 joerg __compactcall int 531 1.31 isaki ustarfs_stat(struct open_file *f, struct stat *sb) 532 1.1 ross { 533 1.1 ross int mode, uid, gid; 534 1.1 ross ust_active_t *ustf; 535 1.1 ross 536 1.1 ross if (f == NULL) 537 1.1 ross return EINVAL; 538 1.1 ross ustf = f->f_fsdata; 539 1.1 ross memset(sb, 0, sizeof *sb); 540 1.1 ross ustarfs_sscanf(ustf->uas_active.ust_mode, "%8o", &mode); 541 1.1 ross ustarfs_sscanf(ustf->uas_active.ust_uid, "%8o", &uid); 542 1.1 ross ustarfs_sscanf(ustf->uas_active.ust_gid, "%8o", &gid); 543 1.1 ross sb->st_mode = mode; 544 1.1 ross sb->st_uid = uid; 545 1.1 ross sb->st_gid = gid; 546 1.1 ross sb->st_size = ustf->uas_filesize; 547 1.1 ross return 0; 548 1.1 ross } 549 1.1 ross 550 1.34 tsutsui 551 1.34 tsutsui #if defined(LIBSA_ENABLE_LS_OP) 552 1.35 christos #include "ls.h" 553 1.34 tsutsui __compactcall void 554 1.34 tsutsui ustarfs_ls(struct open_file *f, const char *pattern) 555 1.34 tsutsui { 556 1.35 christos lsunsup("ustarfs"); 557 1.34 tsutsui return; 558 1.34 tsutsui } 559 1.34 tsutsui #endif 560 1.34 tsutsui 561 1.8 cgd #ifndef LIBSA_NO_FS_CLOSE 562 1.33 joerg __compactcall int 563 1.31 isaki ustarfs_close(struct open_file *f) 564 1.1 ross { 565 1.1 ross if (f == NULL || f->f_fsdata == NULL) 566 1.1 ross return EINVAL; 567 1.26 christos dealloc(f->f_fsdata, sizeof(ust_active_t)); 568 1.1 ross f->f_fsdata = 0; 569 1.1 ross return 0; 570 1.1 ross } 571 1.8 cgd #endif /* !LIBSA_NO_FS_CLOSE */ 572