31
31
#include "mongo_types.h"
32
32
#include "db.h"
33
33
34
+ #include "ext/standard/php_smart_str.h"
35
+
34
36
typedef struct {
35
37
FILE * file ;
36
38
int fd ; /* underlying file descriptor */
@@ -335,6 +337,57 @@ static void add_md5(zval *zfile, zval *zid, mongo_collection *c TSRMLS_DC) {
335
337
}
336
338
}
337
339
340
+ static cleanup_broken_insert (INTERNAL_FUNCTION_PARAMETERS , zval * zid TSRMLS_CC )
341
+ {
342
+ zval * chunks , * files , * criteria_chunks , * criteria_files ;
343
+ char * message = NULL ;
344
+ smart_str tmp_message = { 0 };
345
+ zval * temp_return ;
346
+
347
+ chunks = zend_read_property (mongo_ce_GridFS , getThis (), "chunks" , strlen ("chunks" ), NOISY TSRMLS_CC );
348
+ if (EG (exception )) {
349
+ message = estrdup (Z_STRVAL_P (zend_read_property (mongo_ce_GridFSException , EG (exception ), "message" , strlen ("message" ), NOISY TSRMLS_CC )));
350
+ zend_clear_exception (TSRMLS_C );
351
+ }
352
+
353
+ MAKE_STD_ZVAL (criteria_files );
354
+ array_init (criteria_files );
355
+ zval_add_ref (& zid );
356
+ add_assoc_zval (criteria_files , "_id" , zid );
357
+
358
+ MAKE_STD_ZVAL (criteria_chunks );
359
+ array_init (criteria_chunks );
360
+ zval_add_ref (& zid );
361
+ add_assoc_zval (criteria_chunks , "files_id" , zid );
362
+
363
+ MAKE_STD_ZVAL (temp_return );
364
+ ZVAL_NULL (temp_return );
365
+ MONGO_METHOD1 (MongoCollection , remove , temp_return , chunks , criteria_chunks );
366
+ zval_ptr_dtor (& temp_return );
367
+
368
+ MAKE_STD_ZVAL (temp_return );
369
+ ZVAL_NULL (temp_return );
370
+ MONGO_METHOD1 (MongoCollection , remove , temp_return , getThis (), criteria_files );
371
+ zval_ptr_dtor (& temp_return );
372
+
373
+ zval_ptr_dtor (& criteria_files );
374
+ zval_ptr_dtor (& criteria_chunks );
375
+
376
+ // create the message for the exception
377
+ if (message ) {
378
+ smart_str_appends (& tmp_message , "Could not store file: " );
379
+ smart_str_appends (& tmp_message , message );
380
+ smart_str_0 (& tmp_message );
381
+ efree (message );
382
+ } else {
383
+ smart_str_appends (& tmp_message , "Could not store file for unknown reasons" );
384
+ smart_str_0 (& tmp_message );
385
+ }
386
+ zend_throw_exception (mongo_ce_GridFSException , tmp_message .c , 0 TSRMLS_CC );
387
+ smart_str_free (& tmp_message );
388
+ RETVAL_FALSE ;
389
+ }
390
+
338
391
/*
339
392
* Stores an array of bytes that may not have a filename,
340
393
* such as data from a socket or stream.
@@ -348,6 +401,7 @@ PHP_METHOD(MongoGridFS, storeBytes) {
348
401
char * bytes = 0 ;
349
402
int bytes_len = 0 , chunk_num = 0 , chunk_size = 0 , global_chunk_size = 0 ,
350
403
pos = 0 ;
404
+ int free_options = 0 , revert = 0 ;
351
405
352
406
zval temp ;
353
407
zval * extra = 0 , * zid = 0 , * zfile = 0 , * chunks = 0 , * options = 0 ;
@@ -358,16 +412,9 @@ PHP_METHOD(MongoGridFS, storeBytes) {
358
412
chunks = zend_read_property (mongo_ce_GridFS , getThis (), "chunks" , strlen ("chunks" ), NOISY TSRMLS_CC );
359
413
ensure_gridfs_index (& temp , chunks TSRMLS_CC );
360
414
361
- if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "s|az" , & bytes , & bytes_len , & extra , & options ) == FAILURE ) {
362
- return ;
363
- }
364
-
365
- if (!options ) {
366
- zval * opts ;
367
- MAKE_STD_ZVAL (opts );
368
- array_init (opts );
369
- options = opts ;
370
- }
415
+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "s|aa/" , & bytes , & bytes_len , & extra , & options ) == FAILURE ) {
416
+ return ;
417
+ }
371
418
372
419
// file array object
373
420
MAKE_STD_ZVAL (zfile );
@@ -383,14 +430,30 @@ PHP_METHOD(MongoGridFS, storeBytes) {
383
430
add_assoc_long (zfile , "length" , bytes_len );
384
431
}
385
432
433
+ // options
434
+ if (!options ) {
435
+ zval * opts ;
436
+ MAKE_STD_ZVAL (opts );
437
+ array_init (opts );
438
+ options = opts ;
439
+ free_options = 1 ;
440
+ }
441
+
442
+ // force safe mode
443
+ add_assoc_long (options , "safe" , 1 );
444
+
386
445
// insert chunks
387
446
while (pos < bytes_len ) {
388
447
chunk_size = bytes_len - pos >= global_chunk_size ? global_chunk_size : bytes_len - pos ;
389
448
390
- insert_chunk (chunks , zid , chunk_num , bytes + pos , chunk_size , options TSRMLS_CC );
391
- if (EG (exception )) {
392
- return ;
393
- }
449
+ if (insert_chunk (chunks , zid , chunk_num , bytes + pos , chunk_size , options TSRMLS_CC ) == FAILURE ) {
450
+ revert = 1 ;
451
+ goto cleanup_on_failure ;
452
+ }
453
+ if (EG (exception )) {
454
+ revert = 1 ;
455
+ goto cleanup_on_failure ;
456
+ }
394
457
395
458
// increment counters
396
459
pos += chunk_size ;
@@ -402,11 +465,25 @@ PHP_METHOD(MongoGridFS, storeBytes) {
402
465
403
466
// insert file
404
467
MONGO_METHOD2 (MongoCollection , insert , & temp , getThis (), zfile , options );
405
-
406
- zval_add_ref (& zid );
407
- zval_ptr_dtor (& zfile );
408
-
409
- RETURN_ZVAL (zid , 1 , 1 );
468
+ zval_dtor (& temp );
469
+ if (EG (exception )) {
470
+ revert = 1 ;
471
+ }
472
+
473
+ cleanup_on_failure :
474
+ if (!revert ) {
475
+ RETVAL_ZVAL (zid , 1 , 1 );
476
+ } else {
477
+ cleanup_broken_insert (INTERNAL_FUNCTION_PARAM_PASSTHRU , zid TSRMLS_CC );
478
+ RETVAL_FALSE ;
479
+ }
480
+
481
+ zval_add_ref (& zid );
482
+ zval_ptr_dtor (& zfile );
483
+
484
+ if (free_options ) {
485
+ zval_ptr_dtor (& options );
486
+ }
410
487
}
411
488
412
489
/* add extra fields required for files:
@@ -454,7 +531,7 @@ static int setup_file_fields(zval *zfile, char *filename, int size TSRMLS_DC) {
454
531
* - buf
455
532
*/
456
533
static int insert_chunk (zval * chunks , zval * zid , int chunk_num , char * buf , int chunk_size , zval * options TSRMLS_DC ) {
457
- zval temp ;
534
+ zval temp ;
458
535
zval * zchunk , * zbin ;
459
536
460
537
// create chunk
@@ -480,6 +557,7 @@ static int insert_chunk(zval *chunks, zval *zid, int chunk_num, char *buf, int c
480
557
else {
481
558
MONGO_METHOD1 (MongoCollection , insert , & temp , chunks , zchunk );
482
559
}
560
+ zval_dtor (& temp );
483
561
484
562
// increment counters
485
563
zval_ptr_dtor (& zchunk ); // zid->refcount = 1
@@ -496,6 +574,7 @@ PHP_METHOD(MongoGridFS, storeFile) {
496
574
zval * fh , * extra = 0 , * options = 0 ;
497
575
char * filename = 0 ;
498
576
int chunk_num = 0 , global_chunk_size = 0 , size = 0 , pos = 0 , fd = -1 , safe = 0 ;
577
+ int free_options = 0 , revert = 0 ;
499
578
FILE * fp = 0 ;
500
579
501
580
zval temp ;
@@ -507,16 +586,9 @@ PHP_METHOD(MongoGridFS, storeFile) {
507
586
508
587
ensure_gridfs_index (& temp , chunks TSRMLS_CC );
509
588
510
- if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "z|az" , & fh , & extra , & options ) == FAILURE ) {
511
- return ;
512
- }
513
-
514
- if (!options ) {
515
- zval * opts ;
516
- MAKE_STD_ZVAL (opts );
517
- array_init (opts );
518
- options = opts ;
519
- }
589
+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "z|aa/" , & fh , & extra , & options ) == FAILURE ) {
590
+ return ;
591
+ }
520
592
521
593
if (Z_TYPE_P (fh ) == IS_RESOURCE ) {
522
594
zend_rsrc_list_entry * le ;
@@ -577,6 +649,18 @@ PHP_METHOD(MongoGridFS, storeFile) {
577
649
// chunkSize
578
650
global_chunk_size = get_chunk_size (zfile TSRMLS_CC );
579
651
652
+ // options
653
+ if (!options ) {
654
+ zval * opts ;
655
+ MAKE_STD_ZVAL (opts );
656
+ array_init (opts );
657
+ options = opts ;
658
+ free_options = 1 ;
659
+ }
660
+
661
+ // force safe mode
662
+ add_assoc_long (options , "safe" , 1 );
663
+
580
664
// insert chunks
581
665
while (pos < size || fp == 0 ) {
582
666
int result = 0 ;
@@ -588,32 +672,41 @@ PHP_METHOD(MongoGridFS, storeFile) {
588
672
if (fp ) {
589
673
if ((int )fread (buf , 1 , chunk_size , fp ) < chunk_size ) {
590
674
zend_throw_exception_ex (mongo_ce_GridFSException , 0 TSRMLS_CC , "error reading file %s" , filename );
591
- return ;
675
+ revert = 1 ;
676
+ efree (buf );
677
+ goto cleanup_on_failure ;
592
678
}
593
679
pos += chunk_size ;
594
680
if (insert_chunk (chunks , zid , chunk_num , buf , chunk_size , options TSRMLS_CC ) == FAILURE ) {
595
- break ;
681
+ revert = 1 ;
682
+ efree (buf );
683
+ goto cleanup_on_failure ;
596
684
}
597
685
}
598
686
else {
599
687
result = read (fd , buf , chunk_size );
600
688
if (result == -1 ) {
601
689
zend_throw_exception_ex (mongo_ce_GridFSException , 0 TSRMLS_CC , "error reading filehandle" );
602
- return ;
690
+ revert = 1 ;
691
+ efree (buf );
692
+ goto cleanup_on_failure ;
603
693
}
604
694
pos += result ;
605
695
if (insert_chunk (chunks , zid , chunk_num , buf , result , options TSRMLS_CC ) == FAILURE ) {
606
- break ;
696
+ revert = 1 ;
697
+ efree (buf );
698
+ goto cleanup_on_failure ;
607
699
}
608
700
}
609
701
610
- if (safe && EG (exception )) {
611
- return ;
612
- }
702
+ efree (buf );
613
703
614
- chunk_num ++ ;
704
+ if (safe && EG (exception )) {
705
+ revert = 1 ;
706
+ goto cleanup_on_failure ;
707
+ }
615
708
616
- efree ( buf ) ;
709
+ chunk_num ++ ;
617
710
618
711
if (fp == 0 && result < chunk_size ) {
619
712
break ;
@@ -626,8 +719,7 @@ PHP_METHOD(MongoGridFS, storeFile) {
626
719
}
627
720
628
721
if (EG (exception )) {
629
- zval_ptr_dtor (& zfile );
630
- return ;
722
+ goto cleanup_on_failure ;
631
723
}
632
724
633
725
if (!fp ) {
@@ -636,14 +728,39 @@ PHP_METHOD(MongoGridFS, storeFile) {
636
728
637
729
add_md5 (zfile , zid , c TSRMLS_CC );
638
730
639
- // insert file
640
- MONGO_METHOD2 (MongoCollection , insert , & temp , getThis (), zfile , options );
641
-
642
- // cleanup
643
- zval_add_ref (& zid );
644
- zval_ptr_dtor (& zfile );
645
-
646
- RETURN_ZVAL (zid , 1 , 1 );
731
+ // insert file
732
+ if (!revert ) {
733
+ zval * temp_return ;
734
+
735
+ Z_ADDREF_P (options );
736
+ MAKE_STD_ZVAL (temp_return );
737
+ ZVAL_NULL (temp_return );
738
+ MONGO_METHOD2 (MongoCollection , insert , temp_return , getThis (), zfile , options );
739
+ zval_ptr_dtor (& temp_return );
740
+ Z_DELREF_P (options );
741
+ if (EG (exception )) {
742
+ revert = 1 ;
743
+ }
744
+ }
745
+
746
+ if (!revert ) {
747
+ RETVAL_ZVAL (zid , 1 , 1 );
748
+ }
749
+
750
+ cleanup_on_failure :
751
+ // remove all inserted chunks and main file document
752
+ if (revert ) {
753
+ cleanup_broken_insert (INTERNAL_FUNCTION_PARAM_PASSTHRU , zid TSRMLS_DC );
754
+ RETVAL_FALSE ;
755
+ }
756
+
757
+ // cleanup
758
+ zval_add_ref (& zid );
759
+ zval_ptr_dtor (& zfile );
760
+
761
+ if (free_options ) {
762
+ zval_ptr_dtor (& options );
763
+ }
647
764
}
648
765
649
766
PHP_METHOD (MongoGridFS , findOne ) {
@@ -826,21 +943,25 @@ PHP_METHOD(MongoGridFS, storeUpload) {
826
943
* New GridFS API
827
944
*/
828
945
829
- PHP_METHOD (MongoGridFS , delete ) {
830
- zval * id , * criteria ;
946
+ PHP_METHOD (MongoGridFS , delete )
947
+ {
948
+ zval * id , * criteria ;
949
+ char * str_id ;
950
+ size_t str_len ;
831
951
832
- if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "O " , & id , mongo_ce_Id ) == FAILURE ) {
833
- return ;
834
- }
952
+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "z " , & id ) == FAILURE ) {
953
+ return ;
954
+ }
835
955
836
- MAKE_STD_ZVAL (criteria );
837
- array_init (criteria );
838
- add_assoc_zval (criteria , "_id" , id );
839
- zval_add_ref (& id );
956
+ // Set up criteria array
957
+ MAKE_STD_ZVAL (criteria );
958
+ array_init (criteria );
959
+ add_assoc_zval (criteria , "_id" , id );
960
+ zval_add_ref (& id );
840
961
841
- MONGO_METHOD1 (MongoGridFS , remove , return_value , getThis (), criteria );
962
+ MONGO_METHOD1 (MongoGridFS , remove , return_value , getThis (), criteria );
842
963
843
- zval_ptr_dtor (& criteria );
964
+ zval_ptr_dtor (& criteria );
844
965
}
845
966
846
967
PHP_METHOD (MongoGridFS , get ) {
0 commit comments