]> git.sur5r.net Git - bacula/bacula/blob - bacula/patches/testing/faketape.c
ebl Start a new faketape driver.
[bacula/bacula] / bacula / patches / testing / faketape.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation, which is 
11    listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28
29 #include "faketape.h"
30 #include <dirent.h>
31 #include <sys/mtio.h>
32 #include <ctype.h>
33
34 static int tape_get(int fd, struct mtget *mt_get);
35 static int tape_op(int fd, struct mtop *mt_com);
36 static int tape_pos(int fd, struct mtpos *mt_pos);
37
38 static int dbglevel = 0;
39
40
41 faketape *ftape_list[FTAPE_MAX_DRIVE];
42
43 static faketape *get_tape(int fd)
44 {
45    ASSERT(fd >= 0);
46
47    if (fd >= FTAPE_MAX_DRIVE) {
48       /* error */
49       return NULL;
50    }
51
52    return ftape_list[fd];
53 }
54
55 static bool put_tape(faketape *ftape)
56 {
57    ASSERT(ftape != NULL);
58
59    int fd = ftape->get_fd();
60    if (fd >= FTAPE_MAX_DRIVE) {
61       /* error */
62       return false;
63    }
64    ftape_list[fd] = ftape;
65    return true;
66 }
67
68 int faketape_open(const char *pathname, int flags, int mode)
69 {
70    int fd;
71    faketape *tape = new faketape();
72    fd = tape->open(pathname, flags, mode);
73    if (fd > 0) {
74       put_tape(tape);
75    }
76    return fd;
77 }
78
79 int faketape_read(int fd, void *buffer, unsigned int count)
80 {
81    faketape *tape = get_tape(fd);
82    ASSERT(tape != NULL);
83    return tape->read(buffer, count);
84 }
85
86 int faketape_write(int fd, const void *buffer, unsigned int count)
87 {
88    faketape *tape = get_tape(fd);
89    ASSERT(tape != NULL);
90    return tape->write(buffer, count);
91 }
92
93 int faketape_close(int fd)
94 {
95    faketape *tape = get_tape(fd);
96    ASSERT(tape != NULL);
97    tape->close();
98    delete tape;
99    return 0;
100 }
101
102 int faketape_ioctl(int fd, unsigned long int request, ...)
103 {
104    va_list argp;
105    int result=0;
106
107    faketape *t = get_tape(fd);
108    if (!t) {
109       errno = EBADF;
110       return -1;
111    }
112
113    va_start(argp, request);
114
115 //  switch (request) {
116 //  case MTIOCTOP:
117         result = t->tape_op(va_arg(argp, mtop *));
118 //      break;
119
120 //   case MTIOCGET:
121 //      result = tape_get(fd, va_arg(argp, mtget *));
122 //      break;
123 //
124 //   case MTIOCPOS:
125 //      result = tape_pos(fd, va_arg(argp, mtpos *));
126 //      break;
127 //
128 //   default:
129 //      errno = ENOTTY;
130 //      result = -1;
131 //      break;
132 //   }
133
134    va_end(argp);
135
136    return result;
137 }
138
139 int faketape::tape_op(struct mtop *mt_com)
140 {
141    int result=0;
142    struct stat statp;
143    
144    switch (mt_com->mt_op)
145    {
146    case MTRESET:
147    case MTNOP:
148    case MTSETDRVBUFFER:
149       break;
150
151    default:
152    case MTRAS1:
153    case MTRAS2:
154    case MTRAS3:
155    case MTSETDENSITY:
156       errno = ENOTTY;
157       result = -1;
158       break;
159
160    case MTFSF:                  /* Forward space over mt_count filemarks. */
161       /* we are already at EOT */
162       if (current_file > max_file) {
163          atEOF = true;
164          errno = EIO;
165          result = -1;
166       }
167
168       /* we are at the last file */
169       if (current_file == max_file) {
170          current_file++;
171          atEOF = true;
172       }
173
174       break;
175
176    case MTBSF:                  /* Backward space over mt_count filemarks. */
177       current_file = current_file - mt_op->mt_count;
178       if (current_file < 0) {
179          current_file = 0;
180          errno = EIO;
181          result = -1;
182       }
183       atEOD = false;
184       atEOF = false;
185       atEOM = false;
186       open_file();
187       break;
188
189    case MTFSR:      /* Forward space over mt_count records (tape blocks). */
190 /*
191     file number = 1
192     block number = 0
193    
194     file number = 1
195     block number = 1
196    
197     mt: /dev/lto2: Erreur d'entrée/sortie
198    
199     file number = 2
200     block number = 0
201 */
202       /* tester si on se trouve a la fin du fichier */
203       fseek(cur_fd, SEEK_CUR, tape_info.block_size*mt_op->mt_count);
204       break;
205
206    case MTBSR:      /* Backward space over mt_count records (tape blocks). */
207
208 /*
209    file number = 1
210    block number = -1
211
212    mt: /dev/lto2: Erreur d'entrée/sortie
213
214    file number = 0
215    block number = -1
216 */
217
218       fstat(cur_file, &statp);
219       off_t cur_pos = lseek(cur_fd, 0, SEEK_CUR);
220
221       fseek(cur_fd, SEEK_CUR, tape_info.block_size*mt_op->mt_count);
222       break;
223
224    case MTWEOF:                 /* Write mt_count filemarks. */
225       break;
226
227    case MTREW:                  /* Rewind. */
228       atEOF = atEOD = atEOM = false;
229       current_file = 0;
230       open_file();
231       break;
232
233    case MTOFFL:                 /* put tape offline */
234       // check if can_read/can_write
235       result = 0;
236       break;
237
238    case MTRETEN:                /* Re-tension tape. */
239       result = 0;
240       break;
241
242    case MTBSFM:                 /* not used by bacula */
243       errno = EIO;
244       result = -1;
245       break;
246
247    case MTFSFM:                 /* not used by bacula */
248       errno = EIO;
249       result = -1;
250       break;
251
252    case MTEOM:/* Go to the end of the recorded media (for appending files). */
253 /*
254    file number = 3
255    block number = -1
256 */
257       /* Can be at EOM */
258       atEOF = true;
259       current_block = -1;
260       /* Ne pas creer le fichier si on est a la fin */
261
262       break;
263
264    case MTERASE:
265       atEOD = true;
266       atEOF = false;
267       atEOT = false;
268       current_file = 0;
269       current_block = -1;
270       delete_files(current_file);
271       break;
272
273    case MTSETBLK:
274       break;
275
276    case MTSEEK:
277       break;
278
279    case MTTELL:
280       break;
281
282    case MTFSS:
283       break;
284
285    case MTBSS:
286       break;
287
288    case MTWSM:
289       break;
290
291    case MTLOCK:
292       break;
293
294    case MTUNLOCK:
295       break;
296
297    case MTLOAD:
298       break;
299
300    case MTUNLOAD:
301       break;
302
303    case MTCOMPRESSION:
304       break;
305
306    case MTSETPART:
307       break;
308
309    case MTMKPART:
310       break;
311    }
312 //
313 //   switch (result) {
314 //   case NO_ERROR:
315 //   case -1:   /* Error has already been translated into errno */
316 //      break;
317 //
318 //   default:
319 //   case ERROR_FILEMARK_DETECTED:
320 //      errno = EIO;
321 //      break;
322 //
323 //   case ERROR_END_OF_MEDIA:
324 //      errno = EIO;
325 //      break;
326 //
327 //   case ERROR_NO_DATA_DETECTED:
328 //      errno = EIO;
329 //      break;
330 //
331 //   case ERROR_NO_MEDIA_IN_DRIVE:
332 //      errno = ENOMEDIUM;
333 //      break;
334 //
335 //   case ERROR_INVALID_HANDLE:
336 //   case ERROR_ACCESS_DENIED:
337 //   case ERROR_LOCK_VIOLATION:
338 //      errno = EBADF;
339 //      break;
340 //   }
341 //
342    return result == 0 ? 0 : -1;
343 }
344
345 int faketape::tape_get(struct mtget *mt_get)
346 {
347    return 0;
348 }
349
350 int faketape::tape_pos(struct mtpos *mt_pos)
351 {
352    return 0;
353 }
354
355 int faketape::delete_files(int startfile)
356 {  
357    int cur,max=0;
358    char *p;
359    POOL_MEM tmp;
360    DIR *fp_dir;
361    struct dirent *dir;
362    struct stat statp;
363
364    fp_dir = opendir(this->volume);
365    if (!fp_dir) {
366       this->max_file=0;
367       this->size = 0;
368       return -1;
369    }
370
371    this->size = 0;
372
373    /* search for all digit file */
374    while ((dir = readdir (fp_dir)) != NULL)
375    {
376       Mmsg(tmp, "%s/%s", this->volume, dir->d_name);
377       cur = 0;
378       /* check if d_name contains only digits */
379       for(p = dir->d_name; *p && isdigit(*p); p++)
380       {
381          cur *= 10;
382          cur += *p;
383       }
384       if (!*p && cur) {
385          if (cur >= startfile) { /* remove it */
386             unlink(tmp);
387          } else {
388             if (lstat(tmp.c_str(), &statp) == 0) {
389                this->size += statp.st_size;
390             }
391             max = (max > cur)?max:cur;
392          }
393       }
394    }
395
396    closedir(fp_dir);
397    this->max_file = max;
398    return max;
399 }
400
401 faketape::faketape()
402 {
403    fd = 0;
404    atEOF = 0;
405    atEOM = 0;
406    current_file = 0;
407    current_block = 0;
408    max_file = 0;
409
410    volume = get_pool_memory(PM_NAME);
411    cur_file = get_pool_memory(PM_NAME);
412    cur_info = get_pool_memory(PM_NAME);
413 }
414
415 faketape::~faketape()
416 {
417    free_pool_memory(volume);
418    free_pool_memory(cur_file);
419    free_pool_memory(cur_info);
420 }
421
422 int faketape::get_fd()
423 {
424    return this->fd;
425 }
426
427 int faketape::write(const void *buffer, unsigned int count)
428 {
429    ASSERT(cur_fd > 0);
430    if (current_block == -1) {
431       open_file();
432    }
433    /* remove all file > current_file */
434    return ::write(cur_fd, buffer, count);
435 }
436
437 int faketape::close()
438 {
439    ASSERT(cur_fd > 0);
440    ::close(cur_fd);
441    ::close(fd);
442
443    return 0;
444 }
445
446 int faketape::read(void *buffer, unsigned int count)
447 {
448    ASSERT(cur_fd > 0);
449    if (current_block == -1) {
450       open_file();
451    }
452    return ::read(cur_fd, buffer, count);
453 }
454
455 int faketape::read_volinfo()
456 {
457    struct stat statp;
458    memset(&tape_info, 0, sizeof(FTAPE_FORMAT));
459
460    Dmsg2(0, "Info %p %p\n", cur_info, volume);
461    Mmsg(cur_info, "%s/info", volume);
462    fd = ::open(cur_info, O_CREAT | O_RDWR | O_BINARY, 0640);
463    
464    if (fd < 0) {
465       return -1;
466    }
467    
468    fstat(cur_info, &statp);
469    
470    /* read volume info */
471    int nb = ::read(fd, &tape_info, sizeof(FTAPE_FORMAT));
472    if (nb != sizeof(FTAPE_FORMAT)) { /* new tape ? */
473       Dmsg1(dbglevel, "Initialize %s\n", volume);
474       tape_info.version = 1;
475       tape_info.block_max = 2000000;
476       tape_info.block_size = statp.st_blksize;
477       tape_info.max_file_mark = 2000;
478
479       lseek(fd, SEEK_SET, 0);
480       nb = ::write(fd, &tape_info, sizeof(FTAPE_FORMAT));
481
482       if (nb != sizeof(FTAPE_FORMAT)) {
483          ::close(fd);
484          return -1;
485       }
486    }
487
488    Dmsg0(dbglevel, "read_volinfo OK\n");
489    find_maxfile();
490
491    return fd;
492 }
493
494 int faketape::open(const char *pathname, int uflags, int umode)
495 {
496    Dmsg3(dbglevel, "faketape::open(%s, %i, %i)\n", pathname, uflags, umode);
497    pm_strcpy(volume, pathname);
498
499    struct stat statp;   
500    if (lstat(volume, &statp) != 0) {
501       Dmsg1(dbglevel, "Can't stat on %s\n", volume);
502       return -1;
503    }
504
505    if (!S_ISDIR(statp.st_mode)) {
506       Dmsg1(dbglevel, "%s is not a directory\n", volume);
507       errno = EACCES;
508       return -1;
509    }
510
511    /* open volume descriptor and get this->fd */
512    if (read_volinfo() < 0) {
513       return -1;
514    }
515
516    current_block=-1;
517
518    return fd;
519 }
520
521 int faketape::find_maxfile()
522 {
523    int max=0;
524    int cur;
525    char *p;
526    POOL_MEM tmp;
527    DIR *fp_dir;
528    struct dirent *dir;
529    struct stat statp;
530
531    fp_dir = opendir(this->volume);
532    if (!fp_dir) {
533       max_file=0;
534       return -1;
535    }
536
537    this->size = 0;
538
539    /* search for all digit file */
540    while ((dir = readdir (fp_dir)) != NULL)
541    {
542       Mmsg(tmp, "%s/%s", this->volume, dir->d_name);
543       if (lstat(tmp.c_str(), &statp) == 0) {
544          this->size += statp.st_size;
545       } else {
546          Dmsg1(dbglevel, "Can't stat %s\n", tmp.c_str());
547       }
548       cur = 0;
549       /* TODO: compute size */
550       for(p = dir->d_name; *p && isdigit(*p); p++)
551       {
552          cur *= 10;
553          cur += *p;
554       }
555       if (!*p && cur) {
556          max = (max > cur)?max:cur;
557       }
558    }
559
560    closedir(fp_dir);
561    this->max_file = max;
562    return max;
563 }
564
565 int faketape::open_file() 
566 {
567    if (cur_fd) {
568       ::close(cur_fd);
569    }
570
571    Mmsg(cur_file, "%s/%i", volume, current_file);
572    cur_fd = ::open(cur_file, O_CREAT | O_RDWR | O_BINARY, 0640);
573    if (cur_fd < 0) {
574       return -1;
575    }
576    current_block = 0;
577    max_file = (max_file > current_file)?max_file:current_file;
578
579    return cur_fd;
580
581 }
582
583 void faketape::dump()
584 {
585    Dmsg1(dbglevel, "max_file=%i\n", max_file);
586    Dmsg1(dbglevel, "current_file=%i\n", current_file);
587    Dmsg1(dbglevel, "volume=%s\n", volume);
588    Dmsg1(dbglevel, "cur_info=%s\n", cur_info);
589    Dmsg1(dbglevel, "cur_file=%s\n", cur_file);  
590    Dmsg1(dbglevel, "size=%i\n", size);  
591 }
592
593 #ifdef TEST
594
595 int main()
596 {
597    int fd;
598    printf("Starting FakeTape\n");
599
600    mkdir("/tmp/fake", 0777);
601    fd = faketape_open("/tmp/fake", O_CREAT | O_RDWR | O_BINARY, 0666);
602    if (fd < 0) {
603       perror("open ERR");
604       return 1;
605    }
606
607    faketape *tape = get_tape(fd);
608    tape->dump();
609
610    faketape_close(fd);
611
612    return 0;
613 }
614
615 #endif